為什麼使用innerHTML對元素新增內容後,該元素「子代」的事件監聽器失效?
2021-05-25 18:32 HTML JavaScript
問題描述
- 對
<button id="alert">alert('hello world')</button>加上事件監聽器,使其被點擊後會出現 alert 訊息 - 透過
innerHTML對<div id="target">新增一個<span>標籤(不對<button id="alert">進行任何處理),但新增完畢後,點擊<button id="alert">卻無法出現 alert 訊息了 - 示範用原始碼如下:
See the Pen innerHTML destroying descendants' event listeners by Charlie (@Charlie7779) on CodePen.
原因
innerHTML實際上是「移除原本的內容後,以新的內容取代之」- 就算是新增,也會觸發上述的「移除 ─ 新增」機制,綁定好的事件監聽器的子代元素也會一起被移除
MDN: Setting the value of innerHTML removes all of the element’s descendants and replaces them with nodes constructed by parsing the HTML given in the string htmlString.
- 在示範用的程式碼中,點擊
<button id="replace">對<div id="target">新增一個<span>後,原先綁定了事件監聽器的<button id="alert">已被移除,並被一個新的<button id="alert">取代 - 新的
<button id="alert">沒有任何事件監聽器,故點擊後不會出現 alert 訊息
解決方式
createElement()搭配 appendChild()
See the Pen appendChild by Charlie (@Charlie7779) on CodePen.
- 透過
let span = document.createElement("span")建立一個<span>元素 - 使用
textContent設定span的文字內容 - 執行
target.appendChild(span)將span加為target的子代元素
MDN: The
Node.appendChild()method adds a node to the end of the list of children of a specified parent node.
insertAdjacentHTML()
See the Pen insertAdjacentHTML() by Charlie (@Charlie7779) on CodePen.
關於element.insertAdjacentHTML(position, text):
position參數以下四選一:beforebegin:在element前插入textafterbegin:在element內部、第一個 childNode 前插入textbeforeend:在element內部、最後的 childNode 後插入textafterend:在element後插入text
text:會被轉換為 HTML 節點,可使用 template literal
See the Pen insertAdjacentHTML() -- position by Charlie (@Charlie7779) on CodePen.