為什麼使用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
前插入text
afterbegin
:在element
內部、第一個 childNode 前插入text
beforeend
:在element
內部、最後的 childNode 後插入text
afterend
:在element
後插入text
text
:會被轉換為 HTML 節點,可使用 template literal
See the Pen insertAdjacentHTML() -- position by Charlie (@Charlie7779) on CodePen.