Có thể nối thêm vào innerHTML mà không phá hủy trình lắng nghe sự kiện của con cháu không?


112

Trong mã ví dụ sau, tôi đính kèm một onclicktrình xử lý sự kiện vào khoảng có chứa văn bản "foo". Trình xử lý là một hàm ẩn danh bật lên một alert().

Tuy nhiên, nếu tôi gán cho nút cha innerHTML, onclicktrình xử lý sự kiện này sẽ bị phá hủy - việc nhấp vào "foo" không bật lên hộp cảnh báo.

Điều này có thể sửa chữa được không?

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

Câu hỏi này liên quan đến vấn đề 'nối các trường mới vào biểu mẫu xóa thông tin nhập của người dùng'. Câu trả lời đã chọn khắc phục được cả hai vấn đề này rất tốt.
MattT

Ủy quyền sự kiện có thể được sử dụng để giải quyết vấn đề này.
dasfdsa

Câu trả lời:


126

Thật không may, việc chỉ định innerHTMLgây ra sự phá hủy tất cả các phần tử con, ngay cả khi bạn đang cố nối thêm. Nếu bạn muốn duy trì các nút con (và các trình xử lý sự kiện của chúng), bạn sẽ cần sử dụng các hàm DOM :

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

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

Chỉnh sửa: Giải pháp của Bob, từ các nhận xét. Đăng câu trả lời của bạn, Bob! Nhận tín dụng cho 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);
    }
}

Có công cụ thay thế nào có thể nối thêm một khối HTML tùy ý không?
mike 27/02/09

64
newcontent = document.createElement ('div'); newcontent.innerHTML = tùy ý_blob; while (newcontent.firstChild) mydiv.appendChild (newcontent.firstChild);
bobince

Tốt lắm, Bob! Nếu bạn đăng câu trả lời đó như một câu trả lời được định dạng tốt, tôi sẽ chọn nó.
mike

@bobince - Tôi đã cập nhật câu trả lời của mình với kỹ thuật của bạn, vì bạn chưa tự đăng nó. Nếu bạn tạo câu trả lời của riêng mình, hãy tiếp tục và quay lại câu trả lời của tôi. :-)
Ben Blank

2
Ồ, một điều cuối cùng, bạn sẽ muốn “var myspan”, “var newcontent”, v.v. để tránh vô tình làm đổ các quả cầu.
bobince 27/02/09

85

Sử dụng .insertAdjacentHTML()bảo tồn trình nghe sự kiện và được hỗ trợ bởi tất cả các trình duyệt chính . Đó là một sự thay thế một dòng đơn giản cho .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);

Đối 'beforeend'số chỉ định vị trí trong phần tử để chèn nội dung HTML. Tùy chọn là 'beforebegin', 'afterbegin', 'beforeend', và 'afterend'. Vị trí tương ứng của chúng là:

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

Bạn đã cứu ngày của tôi!
Tural Asgar

Giải pháp tốt nhất. Cảm ơn bạn!
Dawoodjee

3

Bây giờ, là năm 2012 và jQuery có các chức năng thêm và thêm trước thực hiện chính xác điều này, thêm nội dung mà không ảnh hưởng đến nội dung hiện tại. Rất hữu ích.


7
.insertAdjacentHTMLđã được khoảng từ IE4
Esailija

1
@Tynach vâng, nó có, đó là trang web JavaScript của họ ghi lại nó tốt nhất: developer.mozilla.org/en-US/docs/Web/API/Element/…
Jordon Bedwell vào

2
@JordonBedwell, tôi thực sự không hiểu tại sao tôi lại nói những gì tôi đã làm trước đây. Bạn đúng 100%. Tôi cảm thấy như lúc đó tôi đã nhìn vào nó một cách ngắn ngủi và không thể tìm thấy nó, nhưng ... Thành thật mà nói tôi không có lý do gì cả. Esailija thậm chí còn liên kết đến trang đó.
Tynach

OP là không nói về jQuery
André Marcondes Teixeira

2

Như một sự hỗ trợ nhỏ (nhưng có liên quan), nếu bạn sử dụng thư viện javascript như jquery (v1.3) để thực hiện thao tác dom của mình, bạn có thể sử dụng các sự kiện trực tiếp, nhờ đó bạn thiết lập một trình xử lý như:

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

và nó sẽ được áp dụng cho bộ chọn đó mọi lúc trong bất kỳ loại thao tác jquery nào. Đối với các sự kiện trực tiếp, hãy xem: docs.jquery.com/events/live để biết thao tác jquery, hãy xem: docs.jquery.com/manipulation


1
OP là không nói về jQuery
André Marcondes Teixeira

2

Tôi đã tạo đánh dấu của mình để chèn dưới dạng một chuỗi vì nó ít mã hơn và dễ đọc hơn so với làm việc với những thứ lạ mắt.

Sau đó, tôi tạo nó bên trongHTML của một phần tử tạm thời để tôi có thể lấy một phần tử con duy nhất của phần tử đó và gắn vào phần thân.

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 + = 'thêm bất cứ thứ gì bạn muốn';

nó đã làm việc cho tôi. Tôi đã thêm một nút vào văn bản đầu vào bằng giải pháp này


Đây là phương pháp đơn giản nhất mà tôi đã gặp, cảm ơn bạn!
demo7up 19/09/19

4
Nó phá hủy tất cả các sự kiện.
Tural Asgar

1
nó thực sự là một giải pháp như thế nào? nó phá hủy tất cả các sự kiện !!
Tiếng Đan Mạch

1

Có một giải pháp thay thế khác: sử dụng setAttributethay vì thêm trình nghe sự kiện. Như thế này:

<!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

Có, nó có thể xảy ra nếu bạn liên kết các sự kiện bằng cách sử dụng thuộc tính thẻ onclick="sayHi()"trực tiếp trong mẫu tương tự như của bạn <body onload="start()">- cách tiếp cận này tương tự như các khuôn khổ angle / vue / react / etc. Bạn cũng có thể sử dụng <template>để thao tác trên html 'động' như ở đây . Nó không phải là js không phô trương nghiêm ngặt tuy nhiên nó có thể chấp nhận được đối với các dự án nhỏ

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

Mất trình xử lý sự kiện, IMO, là một lỗi trong cách Javascript xử lý DOM. Để tránh hành vi này, bạn có thể thêm những điều sau:

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
Tôi không coi đây là một lỗi. Thay thế một phần tử có nghĩa là bạn thay thế hoàn toàn nó. Nó không nên kế thừa những gì đã có trước đó.
Diodeus - James MacFarlane 27/02/09

Nhưng tôi không muốn thay thế một phần tử; Tôi chỉ muốn nối những cái mới vào phụ huynh.
mike 27/02/09

Nếu bạn thay thế phần tử, tôi sẽ đồng ý, @Diodeus. Nó không phải là .innerHTML có trình xử lý sự kiện, mà là cha của .innerHtml.
Vâng - Jake đó.

2
Chủ sở hữu của innerHTML không mất trình xử lý khi InternalHTML của nó bị thay đổi, chỉ có bất kỳ thứ gì trong nội dung của nó. Và JavaScript không biết rằng bạn chỉ thêm những đứa trẻ mới, vì “x.innerHTML + = y” chỉ là đường cú pháp cho thao tác chuỗi “x.innerHTML = x.innerHTML + y”.
bobince 27/02/09

Bạn không cần phải đính kèm lại mydiv.onclick. Chỉ cú nhấp chuột của nhịp bên trong bị ghi đè bởi innerHTML +=.
Crescent Fresh

0

Bạn có thể làm như thế này:

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

Cách dễ nhất là sử dụng một mảng và đẩy các phần tử vào đó rồi chèn các giá trị tiếp theo của mảng vào mảng một cách động. Đây là mã của tôi:

var namesArray = [];

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

0

Đối với bất kỳ mảng đối tượng nào có tiêu đề và dữ liệu.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

Tôi là một lập trình viên lười biếng. Tôi không sử dụng DOM vì nó có vẻ như phải nhập thêm. Đối với tôi, càng ít mã càng tốt. Đây là cách tôi thêm "bar" mà không thay thế "foo":

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

15
Câu hỏi này được hỏi làm thế nào để làm điều này mà không làm mất xử lý sự kiện, vì vậy câu trả lời là không có liên quan, và đây là những gì btw + = có, đó là cách ngắn hơn
WLF

2
Thật thú vị là trong câu trả lời sai hoàn toàn này, trích dẫn việc tránh nhập thêm để biện minh, khoảng một nửa mã là thừa.
JLRishe
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.