Javascript class 为一个实例设置的事件会触发所有之前的实例
Javascript class events set for an instance fire for all previous instances
我有一个 class 为每个 LI 创建 mousedown
个监听器。但是,单击第一个实例的 LI 会导致为在它之后创建的每个 LI 实例触发事件。如果您创建第 3 个实例,则单击第 1 个实例将导致所有 3 个触发,而单击第 2 个实例将导致第 2 次和第 3 次触发,依此类推。
要复制,运行 jsfiddle 并单击两个链接(一个接一个),这将创建两个 UL 元素,每个元素包含一个 LI 元素。 Alerts()
设置为显示每个事件触发。如果继续单击链接,您将看到事件如何继续叠加。
我是在 javascript 中创建 classes 的新手,所以我显然错过了一些东西,但不明白为什么多个实例的事件不是分开的。如果您想知道,我已经按照允许静态变量和方法的方式创建了 class。我没有使用 jQuery.
我发布了a jsfiddle of the below code
更新
修复了由于为 SO 削减复杂代码而导致的错误。我已经更新以反映在每个 UL 中创建的多个 LI 元素(数字是动态的和数据库驱动的)并且 ID 是唯一的。
<div id="outer">
<a href="#" onclick="edit('g123')">Click here first id=g123</a>
<br>
<a href="#" onclick="edit('g234')">Click here second id=g234</a>
</div>
<script>
listbox = (function (id) {
var currentul = "";
var counter = 0;
function listbox(id) {
this.id = id;
};
// show or hide once all the properties are set
listbox.prototype.go = function () {
this.initlistbox();
this.addlisteners();
}
// create the elements for drag and drop between two list boxes
listbox.prototype.initlistbox = function () {
var _this = this;
var divlist = document.createElement('div');
divlist.style.minHeight = '100px';
divlist.style.width = '300px'
divlist.style.outline = '1px solid blue'
// the UL
var ul = document.createElement('ul');
ul.setAttribute('id', 'ulchosen-' + this.id);
// track which UL is active for keystrokes
ul.addEventListener('click', function (e) {
if (e.stopPropagation) e.stopPropagation();
currentul = this.id;
}, false);
// add the ul to the div
divlist.appendChild(ul);
divouter = document.getElementById("outer");
// add the div to the body
divouter.appendChild(divlist);
// The LI
// create LI elements
for (i=0; i < 4; i++){
var li = document.createElement('li');
counter++;
li.setAttribute('id', 'lb-li-chosen-' + counter);
li.innerHTML = "Hello " + counter + " " + this.id;
ul.appendChild(li);
}
};
listbox.prototype.addlisteners = function () {
var _this = this;
var lis = document.querySelectorAll("[id^='lb-li-']");
for (var i = 0; i < lis.length; i++) {
this.setlilisteners(lis[i]);
}
};
listbox.prototype.setlilisteners = function (el) {
var _this = this;
// click is for non drag, non shift / ctrl
el.addEventListener('click', function (e) {
alert("A: " + _this.id);
e.preventDefault();
return false;
}, false);
// mousedown is to select LI elements
el.addEventListener('mousedown', function (e) {
e.stopPropagation();
e.preventDefault();
alert("B: " + _this.id);
return false;
}, false);
};
return listbox;
})();
function edit(id) {
var a = new listbox(id);
a.go();
}
</script>
每次使用 addEventListener
都会堆叠一个新函数以供执行。 addEventListener
不会删除旧函数。所以你必须为每个元素调用一次。
下面的代码将起作用。
listbox = (function (id) {
var currentul = "";
function listbox(id) {
this.id = id;
};
// show or hide once all the properties are set
listbox.prototype.go = function () {
this.initlistbox();
}
// create the elements for drag and drop between two list boxes
listbox.prototype.initlistbox = function () {
var _this = this;
var divlist = document.createElement('div');
divlist.style.minHeight = '100px';
divlist.style.width = '300px'
divlist.style.outline = '1px solid blue'
// the UL
var ul = document.createElement('ul');
ul.setAttribute('id', 'ulchosen-' + this.id);
// track which UL is active for keystrokes
ul.addEventListener('click', function (e) {
if (e.stopPropagation) e.stopPropagation();
currentul = this.id;
}, false);
// add the ul to the div
divlist.appendChild(ul);
divouter = document.getElementById("outer");
// add the div to the body
divouter.appendChild(divlist);
// The LI
// create LI elements
var li = document.createElement('li');
li.setAttribute('id', 'lb-li-chosen-1');
li.innerHTML = "Hello " + this.id;
ul.appendChild(li);
this.setlilisteners(li);
};
listbox.prototype.setlilisteners = function (el) {
var _this = this;
// click is for non drag, non shift / ctrl
el.addEventListener('click', function (e) {
alert("A: " + _this.id);
e.preventDefault();
return false;
}, false);
// mousedown is to select LI elements
el.addEventListener('mousedown', function (e) {
e.stopPropagation();
e.preventDefault();
alert("B: " + _this.id);
return false;
}, false);
};
return listbox;
})();
function edit(id) {
var a = new listbox(id);
a.go();
}
fiddle 正在创建多个具有相同 ID lb-li-chosen-1
的 LI 元素,这是无效的 HTML。在某些浏览器中,我相信这可能会导致查询选择器返回一个包含多个 LI 元素的数组,结果是每次调用 .addListeners
时,都会将一个新的事件监听器函数添加到目前定义的每个 LI 元素中。
Gustavo 的回答帮助我找到了错误。我没有过滤 LI 元素以仅包含当前 UL,因此对于每个额外的实例,都会再次设置所有 LI 元素的侦听器。他想告诉我这个...所以这里是:
listbox.prototype.addlisteners = function () {
var _this = this;
var lis = document.querySelectorAll("[id^='lb-li-']");
for (var i = 0; i < lis.length; i++) {
// THIS IF STATEMENT WAS MISSING
if (lis[i].parentNode.id.indexOf("-" + this.id) !== -1){
this.setlilisteners(lis[i]);
}
}
};
我有一个 class 为每个 LI 创建 mousedown
个监听器。但是,单击第一个实例的 LI 会导致为在它之后创建的每个 LI 实例触发事件。如果您创建第 3 个实例,则单击第 1 个实例将导致所有 3 个触发,而单击第 2 个实例将导致第 2 次和第 3 次触发,依此类推。
要复制,运行 jsfiddle 并单击两个链接(一个接一个),这将创建两个 UL 元素,每个元素包含一个 LI 元素。 Alerts()
设置为显示每个事件触发。如果继续单击链接,您将看到事件如何继续叠加。
我是在 javascript 中创建 classes 的新手,所以我显然错过了一些东西,但不明白为什么多个实例的事件不是分开的。如果您想知道,我已经按照允许静态变量和方法的方式创建了 class。我没有使用 jQuery.
我发布了a jsfiddle of the below code
更新 修复了由于为 SO 削减复杂代码而导致的错误。我已经更新以反映在每个 UL 中创建的多个 LI 元素(数字是动态的和数据库驱动的)并且 ID 是唯一的。
<div id="outer">
<a href="#" onclick="edit('g123')">Click here first id=g123</a>
<br>
<a href="#" onclick="edit('g234')">Click here second id=g234</a>
</div>
<script>
listbox = (function (id) {
var currentul = "";
var counter = 0;
function listbox(id) {
this.id = id;
};
// show or hide once all the properties are set
listbox.prototype.go = function () {
this.initlistbox();
this.addlisteners();
}
// create the elements for drag and drop between two list boxes
listbox.prototype.initlistbox = function () {
var _this = this;
var divlist = document.createElement('div');
divlist.style.minHeight = '100px';
divlist.style.width = '300px'
divlist.style.outline = '1px solid blue'
// the UL
var ul = document.createElement('ul');
ul.setAttribute('id', 'ulchosen-' + this.id);
// track which UL is active for keystrokes
ul.addEventListener('click', function (e) {
if (e.stopPropagation) e.stopPropagation();
currentul = this.id;
}, false);
// add the ul to the div
divlist.appendChild(ul);
divouter = document.getElementById("outer");
// add the div to the body
divouter.appendChild(divlist);
// The LI
// create LI elements
for (i=0; i < 4; i++){
var li = document.createElement('li');
counter++;
li.setAttribute('id', 'lb-li-chosen-' + counter);
li.innerHTML = "Hello " + counter + " " + this.id;
ul.appendChild(li);
}
};
listbox.prototype.addlisteners = function () {
var _this = this;
var lis = document.querySelectorAll("[id^='lb-li-']");
for (var i = 0; i < lis.length; i++) {
this.setlilisteners(lis[i]);
}
};
listbox.prototype.setlilisteners = function (el) {
var _this = this;
// click is for non drag, non shift / ctrl
el.addEventListener('click', function (e) {
alert("A: " + _this.id);
e.preventDefault();
return false;
}, false);
// mousedown is to select LI elements
el.addEventListener('mousedown', function (e) {
e.stopPropagation();
e.preventDefault();
alert("B: " + _this.id);
return false;
}, false);
};
return listbox;
})();
function edit(id) {
var a = new listbox(id);
a.go();
}
</script>
每次使用 addEventListener
都会堆叠一个新函数以供执行。 addEventListener
不会删除旧函数。所以你必须为每个元素调用一次。
下面的代码将起作用。
listbox = (function (id) {
var currentul = "";
function listbox(id) {
this.id = id;
};
// show or hide once all the properties are set
listbox.prototype.go = function () {
this.initlistbox();
}
// create the elements for drag and drop between two list boxes
listbox.prototype.initlistbox = function () {
var _this = this;
var divlist = document.createElement('div');
divlist.style.minHeight = '100px';
divlist.style.width = '300px'
divlist.style.outline = '1px solid blue'
// the UL
var ul = document.createElement('ul');
ul.setAttribute('id', 'ulchosen-' + this.id);
// track which UL is active for keystrokes
ul.addEventListener('click', function (e) {
if (e.stopPropagation) e.stopPropagation();
currentul = this.id;
}, false);
// add the ul to the div
divlist.appendChild(ul);
divouter = document.getElementById("outer");
// add the div to the body
divouter.appendChild(divlist);
// The LI
// create LI elements
var li = document.createElement('li');
li.setAttribute('id', 'lb-li-chosen-1');
li.innerHTML = "Hello " + this.id;
ul.appendChild(li);
this.setlilisteners(li);
};
listbox.prototype.setlilisteners = function (el) {
var _this = this;
// click is for non drag, non shift / ctrl
el.addEventListener('click', function (e) {
alert("A: " + _this.id);
e.preventDefault();
return false;
}, false);
// mousedown is to select LI elements
el.addEventListener('mousedown', function (e) {
e.stopPropagation();
e.preventDefault();
alert("B: " + _this.id);
return false;
}, false);
};
return listbox;
})();
function edit(id) {
var a = new listbox(id);
a.go();
}
fiddle 正在创建多个具有相同 ID lb-li-chosen-1
的 LI 元素,这是无效的 HTML。在某些浏览器中,我相信这可能会导致查询选择器返回一个包含多个 LI 元素的数组,结果是每次调用 .addListeners
时,都会将一个新的事件监听器函数添加到目前定义的每个 LI 元素中。
Gustavo 的回答帮助我找到了错误。我没有过滤 LI 元素以仅包含当前 UL,因此对于每个额外的实例,都会再次设置所有 LI 元素的侦听器。他想告诉我这个...所以这里是:
listbox.prototype.addlisteners = function () {
var _this = this;
var lis = document.querySelectorAll("[id^='lb-li-']");
for (var i = 0; i < lis.length; i++) {
// THIS IF STATEMENT WAS MISSING
if (lis[i].parentNode.id.indexOf("-" + this.id) !== -1){
this.setlilisteners(lis[i]);
}
}
};