İ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.