使用Handlebar.js个模板给多个按钮添加onclick事件监听器,只有最后一个有效
Add onclick event listeners to multiple buttons with Handlebar.js templates, only the last one is effective
我正在编写一个网络应用程序作为家庭作业项目,它使用 websocket 从服务器接收消息并使用 handlebars.js 在 html 上显示它们。
我正在尝试使用以下代码实现删除消息的功能:
document.addEventListener('DOMContentLoaded', () => {
...
let message_container = document.querySelector("#message_container");
const message_template = Handlebars.compile(document.querySelector("#message_template").innerHTML);
const delete_button_template = Handlebars.compile(document.querySelector("#delete_button_template").innerHTML);
function addDeleteButton(id) {
let con = delete_button_template({"message_id": id}); //line #1
document.querySelector("#content_" + id).innerHTML += con;
document.querySelector("#delete_button_" + id).onclick = function () {
const msg_id = event.target.dataset.message_id;
const msg = document.querySelector("#message_" + msg_id);
const blank = document.querySelector("#message_" + msg_id + "_newline");
msg.parentElement.removeChild(msg);
blank.parentElement.removeChild(blank);
}
}
添加消息到DOM的函数很简单:
function newMessage(i) {
let msg = message_template({
"message_id": i.message_id,
"username": ...,
"timestamp": ...,
"content": ...
});
message_container.innerHTML += msg;
addDeleteButton(i.message_id);
}
删除按钮的 handlebars.js 模板插入 HTML 如下:
<button id="delete_button_{{ message_id }}" data-message_id="{{ message_id }}" class="btn btn-primary">
Delete
</button>
但是,每次我向 DOM 添加新消息(包括删除按钮)时,所有以前的按钮都会丢失它们的 onclick() 事件侦听器。
chrome 检查员清楚地显示了这一点,它发生在第 1 行:
The 4th button has an event listener registered.
Adding the 5th button
The onclick event of the 4th button disappeared.
一个明确的解决方法是将 onclick 调用嵌入到 html 属性中。
但是为什么我不能像给定的代码那样注册事件监听器呢?
问题出在以下行:
message_container.innerHTML += msg;
我们正在使用 Handlebars 生成一个新的 HTML 字符串,我们将其存储到 msg
变量中。然后我们想要 将新的 HTML 添加 到 #message_container
DOM 元素。
然而,message_container.innerHTML += msg
不是只是将我们的新HTML附加到#message_container
,而是替换 #message_container
!
的所有后代 DOM 节点
发生的事情的细目是:
- 我们得到DOM中
#message_container
的后代节点,字符串化为HTML字符串
msg
连接到这个新 HTML 字符串的末尾。
- 新的HTML字符串替换
#message_container
的innerHTML
。
这里的重要部分是替换。当#message_container
的innerHTML
被替换时,它的所有后代节点都被替换。因此,您之前附加 onclick
个侦听器的所有 <button>
都已从 DOM.
中删除
防止每次我们想添加 <button>
时都替换 #message_container
的所有子项的一种方法是使用 Node.appendChild()
API。生成的代码如下所示:
// message_container.innerHTML += msg; // TODO: Replace this line with the below.
const node = document.createElement('div');
node.innerHTML = msg;
message_container.appendChild(node);
我创建了一个fiddle供参考。
我正在编写一个网络应用程序作为家庭作业项目,它使用 websocket 从服务器接收消息并使用 handlebars.js 在 html 上显示它们。
我正在尝试使用以下代码实现删除消息的功能:
document.addEventListener('DOMContentLoaded', () => {
...
let message_container = document.querySelector("#message_container");
const message_template = Handlebars.compile(document.querySelector("#message_template").innerHTML);
const delete_button_template = Handlebars.compile(document.querySelector("#delete_button_template").innerHTML);
function addDeleteButton(id) {
let con = delete_button_template({"message_id": id}); //line #1
document.querySelector("#content_" + id).innerHTML += con;
document.querySelector("#delete_button_" + id).onclick = function () {
const msg_id = event.target.dataset.message_id;
const msg = document.querySelector("#message_" + msg_id);
const blank = document.querySelector("#message_" + msg_id + "_newline");
msg.parentElement.removeChild(msg);
blank.parentElement.removeChild(blank);
}
}
添加消息到DOM的函数很简单:
function newMessage(i) {
let msg = message_template({
"message_id": i.message_id,
"username": ...,
"timestamp": ...,
"content": ...
});
message_container.innerHTML += msg;
addDeleteButton(i.message_id);
}
删除按钮的 handlebars.js 模板插入 HTML 如下:
<button id="delete_button_{{ message_id }}" data-message_id="{{ message_id }}" class="btn btn-primary">
Delete
</button>
但是,每次我向 DOM 添加新消息(包括删除按钮)时,所有以前的按钮都会丢失它们的 onclick() 事件侦听器。
chrome 检查员清楚地显示了这一点,它发生在第 1 行:
The 4th button has an event listener registered.
Adding the 5th button
The onclick event of the 4th button disappeared.
一个明确的解决方法是将 onclick 调用嵌入到 html 属性中。 但是为什么我不能像给定的代码那样注册事件监听器呢?
问题出在以下行:
message_container.innerHTML += msg;
我们正在使用 Handlebars 生成一个新的 HTML 字符串,我们将其存储到 msg
变量中。然后我们想要 将新的 HTML 添加 到 #message_container
DOM 元素。
然而,message_container.innerHTML += msg
不是只是将我们的新HTML附加到#message_container
,而是替换 #message_container
!
发生的事情的细目是:
- 我们得到DOM中
#message_container
的后代节点,字符串化为HTML字符串 msg
连接到这个新 HTML 字符串的末尾。- 新的HTML字符串替换
#message_container
的innerHTML
。
这里的重要部分是替换。当#message_container
的innerHTML
被替换时,它的所有后代节点都被替换。因此,您之前附加 onclick
个侦听器的所有 <button>
都已从 DOM.
防止每次我们想添加 <button>
时都替换 #message_container
的所有子项的一种方法是使用 Node.appendChild()
API。生成的代码如下所示:
// message_container.innerHTML += msg; // TODO: Replace this line with the below.
const node = document.createElement('div');
node.innerHTML = msg;
message_container.appendChild(node);
我创建了一个fiddle供参考。