如何在javascript中动态创建事件和事件处理程序
How do I dynamically create events and event handlers in javascript
我试图通过使用for循环来动态创建具有唯一侦听器和处理程序的按钮,但不幸的是,我一定做错了什么,因为只有最后一个按钮可以工作。更令人惊讶的是,当点击最后一个按钮而不是"按钮3"时,它会返回"按钮4"
Bellow是代码,这是一个jsfiddlehttp://jsfiddle.net/y69JC/4/
HTML:
<body>
<div id="ui">
some text ...
</div>
</body>
Javascript:
var uiDiv = document.getElementById('ui');
uiDiv.innerHTML = uiDiv.innerHTML + '<br>';
var results = ["Button one","Button two","Button three","Button four"];
for(var n=0;n<results.length;n++)
{
uiDiv.innerHTML = uiDiv.innerHTML + '<button id="connect'+n+'">option'+n+':'+results[n]+'</button><br>';
var tempId = document.getElementById('connect'+n);
tempId.addEventListener('click', function(){console.log("Button No."+n)}, false);
}
谢谢!
当您需要闭包时,这是一个经典的情况:更改为:
var uiDiv = document.getElementById('ui');
uiDiv.innerHTML = uiDiv.innerHTML + '<br>';
var results = ["Button one", "Button two", "Button three", "Button four"];
for (var n = 0; n < results.length; n++) {
// Note: do not use .innerHTML. Create new element programatically
// and then use .appendChild() to add it to the parent.
var button = document.createElement('button');
button.id = 'connect' + n;
button.textContent = 'option' + n + ':' + results[n];
uiDiv.appendChild(button);
button.addEventListener('click', /* this is an inline function */ (function (n2) {
// Here we'll use n2, which is equal to the current n value.
// Value of n2 will not change for this block, because functions
// in JS do create new scope.
// Return the actual 'click' handler.
return function () {
console.log("Button No." + n2)
};
})(n)); // Invoke it immediately with the current n value
}
原因是for
循环不会创建作用域,因此"Button No. " + n
总是使用等于results
数组中元素数的n
进行求值。
需要做的是创建一个接受n
作为参数的内联函数,并立即用当前值n
调用它。然后,此函数将返回单击事件的实际处理程序。请看这个答案以获得一个简单明了的例子。
编辑:您的代码正在使用innerHTML
属性在循环中添加新按钮。它被破坏了,因为每次使用uiDiv.innerHTML = ...
进行分配时,都会删除该div中以前存在的所有内容,并从头开始重新创建它们。这导致剥离以前附加的所有事件处理程序。从示意图上看,它是这样的:
uiDiv.innerHTML = ""
// First iteration of for-loop
uiDiv.innerHTML === <button1 onclick="...">
// Second iteration of for-loop
// 'onclick' handler from button1 disappeared
uiDiv.innerHTML === <button1> <button2 onclick="...">
// Third iteration of for-loop
// 'onclick' handler from button2 disappeared
uiDiv.innerHTML === <button1> <button2> <button3 onclick="...">
您可以编写
onclick = 'myFunction(this.id):'
在按钮中,然后稍后:
function myFunction(idNum){console.log("Button No."+idNum);}
这里还有一些你可能想要实现的改进:
uiDiv.innerHTML = uiDiv.innerHTML + ....;
uiDiv.innerHTML += ....;
你还想在循环之前声明"uiDivContent",然后写:
uiDiv.innerHTML = uiDivContent;
事件处理程序绑定到n
,在事件触发时其值为results.length
。
您必须通过复制来关闭n
的值,也可以通过调用函数来完成。这种构造被称为闭包。
for(var n=0;n<results.length;n++)
{
uiDiv.innerHTML = uiDiv.innerHTML + '<button id="connect'+n+'">option'+n+':'+results[n]+'</button><br>';
var tempId = document.getElementById('connect'+n);
tempId.addEventListener('click', (function(bound_n) {
console.log("Button No."+ bound_n);
})(n)), false); // <-- immediate invocation
}
如果n
是一个对象,这将不起作用,因为对象(与标量不同)是通过引用传递的。
避免在所有for循环中编写闭包的一个好方法是不使用for循环,而是使用带有回调的映射函数。在这种情况下,你的回调就是你的闭包,所以你可以免费获得预期的行为:
function array_map(array, func) {
var target = [], index, clone, len;
clone = array.concat([]); // avoid issues with delete while iterate
len = clone.length;
for (index = 0; index < len; index += 1) {
target.push(func(clone[index], index));
}
return target;
}
array_map(results, function (value, n) {
uiDiv.innerHTML = uiDiv.innerHTML
+ '<button id="connect'+n+'">option'+n+':'+results[n]+'</button><br>';
var tempId = document.getElementById('connect'+n);
tempId.addEventListener('click', function(){console.log("Button No."+n)}, false);
});
- 我可以使用jquery和AJAX来调用cgi-bin脚本,然后添加消息事件来处理服务器发送事件吗
- JS - 无法在自定义事件的处理程序中将其指向调用方
- 如何创建自定义事件来处理所有转换结束事件
- 如何将参数传递给事件的处理程序
- JavaScript 中的事件处理程序如何由事件循环处理
- jQuery点击事件/事件冒泡问题,当尝试突出显示一个元素并同时选中一个复选框
- onclick事件无法处理javascript中的链接
- 从jQuery处理程序中获取事件默认处理程序的结果
- 在事件上填充数组,并在事件函数处理程序外部访问它
- 理解事件委托处理
- 事件监听器处理堆叠/重叠的画布元素
- 等待事件被处理以继续执行触发该事件的函数
- 暂停在执行拖放时显示窗口的拖放事件的处理;在网格之间下降
- 服务器发送事件-事件流-触发一个PHP服务器端事件
- Javascript事件未处理脚本
- Node.js:如何在错误事件时处理域模块中的请求对象
- 在JavaScript中将一系列DOMNodeInserted事件作为单个事件进行处理
- onclick事件无法处理图像
- 事件监听器处理headtrackr.js
- 在keydown事件中处理某些键时遵从默认行为