我正试图在for循环中为一堆新创建的div添加一个点击事件侦听器。我遇到的问题是,只有最后一个div保留其事件侦听器。我读过关于闭包的文章,也读过其他几篇帖子、问题及其答案,据我所知,我已经正确设置了它。但它对我来说仍然不起作用。只有最后一个要迭代的div接收事件侦听器。
function edit_entry(k) {
wrd_input.value = k;
def_input.value = lexicon[k][1];
wrd_input.onkeyup();
delete lexicon[k];
rewrite_entries();
}
function rewrite_entries(keys = null) {
if (keys === null) { keys = []; }
let sorted_keys = sort_lex_keys();
lex_body.style.color = 'rgb(200, 200, 200)';
lex_body.innerHTML = '';
sorted_keys.forEach((key) => {
if (!keys.length || keys.includes(key)) {
lex_body.innerHTML +=
`<div class='lex-entry' id=${key}><i>${key}</i>n<p class='pronunciation'>${lexicon[key][0]}</p>${lexicon[key][1]}</div>n`;
let entry = document.getElementById(key)
entry.addEventListener('click', edit_entry.bind(this, key) );
}
});
}
上述相关代码的当前状态。如果有人知道这个问题,那将是非常有帮助的。如果相关,此代码通过Electron(17.0.0(运行
尝试使用匿名箭头函数而不是绑定的解决方案:
entry.addEventListener('click', () => edit_entry(key) );
产生相同的结果。
更新:更改某个内容的.ninnerHTML属性显然会剥离所有事件侦听器。因此,解决方案只是在js中完全创建元素,将其添加到容器中,然后添加监听器。对forEach
循环的这种更改解决了问题:
sorted_keys.forEach((key) => {
if (!keys.length || keys.includes(key)) {
let entry = document.createElement('div');
entry.className = 'lex-entry';
let word = document.createElement('p');
word.appendChild( document.createTextNode(key) );
word.style.fontStyle = 'italic';
let pron = document.createElement('p');
pron.className = 'pronunciation';
pron.appendChild( document.createTextNode(lexicon[key][0]) );
let defn = document.createTextNode(lexicon[key][1]);
entry.append(word, pron, defn);
entry.addEventListener('click', () => edit_entry(key) );
lex_body.appendChild(entry);
所以我想到了一些事情:
首先,edit_entry.bind(this, key);
:你确定this
指向你想要的吗?它应该指向window
对象。此外,是否有任何理由为该特定函数绑定上下文?
其次是innerHTML
:一般不鼓励直接使用innerHTML
。我不知道当浏览器布局更改为innerHTML
时,当您调用getElementById
时,div
可能不在页面上。作为替代方案,您可以尝试document.createElement("div")
,相应地设置其属性,最后将其附加到lex_body
。
编辑
来自mdn:
请注意,使用innerHTML附加html元素(例如el.innerHTML+="链接"(将导致删除任何以前设置的事件侦听器。也就是说,在以这种方式附加任何HTML元素之后,您将无法侦听以前设置的事件侦听器。
我认为每次用this
绑定函数都会覆盖每次的绑定,这应该是你只得到最后一个事件的原因。
在forEach
lambda内部,this
关键字指的是调用forEach
而不是rewrite_entries
函数的内部类。尝试不绑定呼叫,如下所示:
entry.addEventListener('click', () => edit_entry(key) );