İnsandan gelenlerin olay dinleyicilerini yok etmeden innerHTML'ye eklemek mümkün müdür?


112

Aşağıdaki örnek kodda, bir onclick "foo" metnini içeren yayılma alanına olay işleyicisi . İşleyici, bir alert().

Ancak, üst düğüme atarsam innerHTML , bu onclickolay işleyicisi yok edilir - "foo" düğmesine tıklamak uyarı kutusunu açmaz.

Bu düzeltilebilir mi?

<html>
 <head>
 <script type="text/javascript">

  function start () {
    myspan = document.getElementById("myspan");
    myspan.onclick = function() { alert ("hi"); };

    mydiv = document.getElementById("mydiv");
    mydiv.innerHTML += "bar";
  }

 </script>
 </head>

 <body onload="start()">
   <div id="mydiv" style="border: solid red 2px">
     <span id="myspan">foo</span>
   </div>
 </body>

</html>

Bu soru 'forma yeni alanlar eklemek kullanıcı girişini siler' problemiyle ilgilidir. Seçilen cevap, bu iki sorunu da çok güzel bir şekilde çözüyor.
— MattT

Bu sorunu çözmek için olay yetkilendirme kullanılabilir.
— dasfdsa

Yanıtlar:


127

Ne yazık ki, atama, eklemeye innerHTMLçalışsanız bile tüm alt öğelerin yok olmasına neden olur. Alt düğümleri (ve bunların olay işleyicilerini) korumak istiyorsanız, DOM işlevlerini kullanmanız gerekir :

function start() {
    var myspan = document.getElementById("myspan");
    myspan.onclick = function() { alert ("hi"); };

    var mydiv = document.getElementById("mydiv");
    mydiv.appendChild(document.createTextNode("bar"));
}

Düzenle: Bob'un yorumlardan çözümü. Cevabını gönder Bob! Bunun için kredi alın. :-)

function start() {
    var myspan = document.getElementById("myspan");
    myspan.onclick = function() { alert ("hi"); };

    var mydiv = document.getElementById("mydiv");
    var newcontent = document.createElement('div');
    newcontent.innerHTML = "bar";

    while (newcontent.firstChild) {
        mydiv.appendChild(newcontent.firstChild);
    }
}

Keyfi bir HTML bloğu ekleyebilecek bir yedek var mı?
— mike

64
newcontent = document.createElement ('div'); newcontent.innerHTML = arbitrary_blob; while (newcontent.firstChild) mydiv.appendChild (newcontent.firstChild);
— bobince

Aferin Bob! Bunu iyi biçimlendirilmiş bir cevap olarak gönderirseniz, onu seçerim.
— mike

@bobince - Henüz kendiniz göndermediğiniz için cevabımı tekniğinizle güncelledim. Kendi cevabınızı yaratırsanız, devam edin ve benimkini geri alın. :-)
— Ben Blank

2
Oh, son bir şey, kazara küresellerin dökülmesini önlemek için "var myspan", "var newcontent" vb. İsteyeceksiniz.
— bobince

85

Kullanmak .insertAdjacentHTML()olay dinleyicilerini korur ve tüm büyük tarayıcılar tarafından desteklenir . Tek satırlık basit bir alternatif .innerHTML.

var html_to_insert = "<p>New paragraph</p>";

// with .innerHTML, destroys event listeners
document.getElementById('mydiv').innerHTML += html_to_insert;

// with .insertAdjacentHTML, preserves event listeners
document.getElementById('mydiv').insertAdjacentHTML('beforeend', html_to_insert);

Bağımsız 'beforeend'değişken, HTML içeriğinin öğede nereye ekleneceğini belirtir. Seçenekler şunlardır 'beforebegin', 'afterbegin', 'beforeend', ve 'afterend'. İlgili yerleri şunlardır:

<!-- beforebegin -->
<div id="mydiv">
  <!-- afterbegin -->
  <p>Existing content in #mydiv</p>
  <!-- beforeend -->
</div>
<!-- afterend -->

Günümü kurtardın!
— Tural Asgar

En iyi çözüm. Teşekkür ederim!
— Dawoodjee

3

Şimdi, 2012 ve jQuery, tam olarak bunu yapan, mevcut içeriği etkilemeden içerik ekleyen ekleme ve başa ekleme işlevlerine sahiptir. Çok kullanışlı.



1
@Tynach evet öyle, onu en iyi belgeleyen kendi JavaScript sitesidir: developer.mozilla.org/en-US/docs/Web/API/Element/…
— Jordon Bedwell

2
@JordonBedwell, dürüst olmak gerekirse daha önce ne yaptığımı neden söylediğime dair hiçbir fikrim yok. % 100 haklısın. Kısa bir süreliğine baktığım ve bulamadığım zaman gibi hissediyorum, ama ... Açıkçası hiçbir mazeretim yok. Esailija bu sayfaya bağlantı bile veriyor.
— Tynach


2

Küçük (ancak ilişkili) bir yardım olarak, dom manipülasyonunuzu yapmak için jquery (v1.3) gibi bir javascript kitaplığı kullanırsanız, aşağıdaki gibi bir işleyici oluşturduğunuz canlı olaylardan yararlanabilirsiniz:

 $("#myspan").live("click", function(){
  alert('hi');
});

ve her türlü jquery manipülasyonu sırasında her zaman bu seçiciye uygulanacaktır. Canlı etkinlikler için bkz: docs.jquery.com/events/live jquery manipülasyon için bkz: docs.jquery.com/manipulation


1
OP
— jQuery'den

2

İşaretlememi bir dize olarak eklemek için oluşturdum çünkü daha az kod ve fantezi dom şeyleriyle çalışmaktan daha kolay okunur.

Sonra onu geçici bir öğenin iç HTML'sini yaptım, böylece o öğenin bir ve tek çocuğunu alıp vücuda tutturabileyim.

var html = '<div>';
html += 'Hello div!';
html += '</div>';

var tempElement = document.createElement('div');
tempElement.innerHTML = html;
document.getElementsByTagName('body')[0].appendChild(tempElement.firstChild);

2

something.innerHTML + = 'ne isterseniz ekleyin';

benim için çalıştı. Bu çözümü kullanarak bir giriş metnine bir düğme ekledim


Bu karşılaştığım en basit yöntemdi teşekkür ederim!
— demo7up

4
Tüm olayları yok eder.
— Tural Asgar

1
gerçekten nasıl bir çözüm? tüm olayları yok eder !!
— Danimarka

1

Başka bir alternatif daha var: setAttributebir olay dinleyicisi eklemek yerine kullanmak . Bunun gibi:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Demo innerHTML and event listeners</title>
<style>
    div {
        border: 1px solid black;
        padding: 10px;
    }
</style>
</head>
<body>
    <div>
        <span>Click here.</span>
    </div>
    <script>
        document.querySelector('span').setAttribute("onclick","alert('Hi.')");
        document.querySelector('div').innerHTML += ' Added text.';
    </script>
</body>
</html>


1

Evet, tag özniteliğini kullanarak olayları onclick="sayHi()"doğrudan sizinki gibi şablonda bağlarsanız mümkündür <body onload="start()">- bu yaklaşım, angular / vue / react / etc çerçevelerine benzer. Burada olduğu<template> gibi 'dinamik' html üzerinde çalışmak için de kullanabilirsiniz . Kesinlikle göze batmayan js değil, ancak küçük projeler için kabul edilebilir

function start() {
  mydiv.innerHTML += "bar";
}

function sayHi() {
  alert("hi");
}
<body onload="start()">
  <div id="mydiv" style="border: solid red 2px">
    <span id="myspan" onclick="sayHi()">foo</span>
  </div>
</body>


0

Olay işleyicilerini kaybetmek, IMO, Javascript’in DOM’u işleme biçiminde bir hatadır. Bu davranışı önlemek için aşağıdakileri ekleyebilirsiniz:

function start () {
  myspan = document.getElementById("myspan");
  myspan.onclick = function() { alert ("hi"); };

  mydiv = document.getElementById("mydiv");
  clickHandler = mydiv.onclick;  // add
  mydiv.innerHTML += "bar";
  mydiv.onclick = clickHandler;  // add
}

2
Bunu bir hata olarak görmüyorum. Bir öğeyi değiştirmek, onu tamamen değiştirdiğiniz anlamına gelir. Daha önce orada olanı miras almamalıdır.
— Diodeus - James MacFarlane

Ama bir öğeyi değiştirmek istemiyorum; Sadece yenilerini ebeveyne eklemek istiyorum.
— mike

Elemanı değiştiriyor olsaydın, kabul ediyorum @Diodeus. Olay işleyicisine sahip olan .innerHTML değil, .innerHtml'nin üst öğesidir.
— Evet - şu Jake.

2
İnnerHTML'nin sahibi, innerHTML değiştirildiğinde işleyicileri kaybetmez, yalnızca içeriğindeki her şeyi kaybeder. Ve JavaScript, "x.innerHTML + = y", "x.innerHTML = x.innerHTML + y" dizge işlemi için yalnızca sözdizimsel şeker olduğundan, yalnızca yeni alt öğeler eklediğinizi bilmiyor.
— bobince

Yeniden bağlamanıza gerek yok mydiv.onclick. Yalnızca iç aralık onclick tarafından geçersiz kılınır innerHTML +=.
— Crescent taze

0

Bunu şu şekilde yapabilirsin:

var anchors = document.getElementsByTagName('a'); 
var index_a = 0;
var uls = document.getElementsByTagName('UL'); 
window.onload=function()          {alert(anchors.length);};
for(var i=0 ; i<uls.length;  i++)
{
    lis = uls[i].getElementsByTagName('LI');
    for(var j=0 ;j<lis.length;j++)
    {
        var first = lis[j].innerHTML; 
        string = "<img src=\"http://g.etfv.co/" +  anchors[index_a++] + 
            "\"  width=\"32\" 
        height=\"32\" />   " + first;
        lis[j].innerHTML = string;
    }
}

0

En kolay yol, bir dizi kullanmak ve içine öğeler göndermek ve ardından dizinin sonraki değerlerini diziye dinamik olarak eklemektir. İşte kodum:

var namesArray = [];

function myclick(){
    var readhere = prompt ("Insert value");
    namesArray.push(readhere);
    document.getElementById('demo').innerHTML= namesArray;
}

0

Başlık ve veri içeren herhangi bir nesne dizisi için.jsfiddle

https://jsfiddle.net/AmrendraKumar/9ac75Lg0/2/

<table id="myTable" border='1|1'></table>

<script>
  const userObjectArray = [{
    name: "Ajay",
    age: 27,
    height: 5.10,
    address: "Bangalore"
  }, {
    name: "Vijay",
    age: 24,
    height: 5.10,
    address: "Bangalore"
  }, {
    name: "Dinesh",
    age: 27,
    height: 5.10,
    address: "Bangalore"
  }];
  const headers = Object.keys(userObjectArray[0]);
  var tr1 = document.createElement('tr');
  var htmlHeaderStr = '';
  for (let i = 0; i < headers.length; i++) {
    htmlHeaderStr += "<th>" + headers[i] + "</th>"
  }
  tr1.innerHTML = htmlHeaderStr;
  document.getElementById('myTable').appendChild(tr1);

  for (var j = 0; j < userObjectArray.length; j++) {
    var tr = document.createElement('tr');
    var htmlDataString = '';
    for (var k = 0; k < headers.length; k++) {
      htmlDataString += "<td>" + userObjectArray[j][headers[k]] + "</td>"
    }
    tr.innerHTML = htmlDataString;
    document.getElementById('myTable').appendChild(tr);
  }

</script>

-5

Ben tembel bir programcıyım. DOM kullanmıyorum çünkü fazladan yazma gibi görünüyor. Bana göre ne kadar az kod o kadar iyi. "Foo" yerine "bar" kelimesini şu şekilde eklerim:

function start(){
var innermyspan = document.getElementById("myspan").innerHTML;
document.getElementById("myspan").innerHTML=innermyspan+"bar";
}

15
Bu soru, olay işleyicilerini kaybetmeden bunun nasıl yapılacağını soruyor, bu yüzden cevabınız alakalı değil ve btw bu + ='nin yaptığı şey, ki bu çok daha kısa
— wlf

2
Gerekçe olarak fazladan yazmaktan kaçınmayı gösteren bu tamamen yanlış cevapta, kodun yaklaşık yarısının gereksiz olması çok komik.
— JLRishe
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.