动态创建的 js 脚本 onClick 函数变量不绑定当前值
dynamically created js script onClick function variables not binding at current value
newButton.onclick = function() {
launchForm(
this,
incoming[(10 * (incoming.length / fields)) + z],
incoming[(48 * (incoming.length / fields)) + z]);
};
因此,当我动态生成其中的 4 个按钮时,这四个按钮中的每一个都将第一个按钮的信息传递到函数 launchForm 中。我怀疑这是因为当变量 z 完成它的 for 语句时它返回到 0。如果是这样的话,而不是 + z 是 + 1 按钮 1 和 + z 是 + 2 按钮 2 它变成 + z 是 + 0对于所有按钮。
我该如何解决这个问题?谢谢
编辑:已添加以响应更多信息请求:
var newButton = document.createElement('button');
newButton.className = 'pure-button pure-button-primary mikeButton';
newButton.innerHTML='Launch Form';
newDiv4.appendChild(newButton);
所以我对这一切都很陌生,所以我可能用错了术语。我理解页面加载后创建的项目被认为是动态的。 --- 虽然我是新手,但我非常有信心问题出在我最初提出的问题上。通过设置警报和测试,我可以看到第一个按钮完全正常工作,并且所有适当的参数都完美传递。只是按钮 2、3 和 4 也会启动按钮 1 启动的内容。 Incoming.length不变,字段不变。与创建 newButton 的第一个实例到第二个实例时唯一不同的是 z。 --- 当我在创建第二个、第三个和第四个按钮后立即设置警报时,它们会准确显示应该传递的参数。但是在创建它们的函数完成后(基于使用 z 作为变量的 for 语句),它们转换回就好像 z 是 0 并使用按钮 1 的参数(因为在按钮 1 的参数中 z 等于 0)。我只是将 + 1、+2、+3 硬编码到代码中而不是 z,但是创建的按钮数量取决于查询。有时 1 个按钮,有时 10 个。所以这真的不是一个选择。
希望对您有所帮助。
ES5 不使用块上下文,而是在函数上下文上运行。这意味着在 for
循环中您必须立即使用索引变量,否则如果您(例如)在回调函数中引用它,您将获得回调执行期间该变量的值。
有多种方法可以解决这个问题,可能最简单的方法是在代码中演示:
"use strict";
// first off, using [].forEach.call has some cons so we should have
// a way to convert a NodeList to an Array
var toArray = function(input) {
var output = [];
// check if we have an array-like object
if (input && typeof input.length === 'undefined') { return; }
for (var i = 0; i < input.length; i++) {
output.push(input[i]);
}
return output;
}
// we get lists that contain links to parse
var linkLists = document.getElementsByClassName('link-list');
// and one div to store buttons
var buttonDiv = document.getElementById('buttons');
// we convert the NodeLists to arrays to get the forEach function
toArray(linkLists).forEach(function(list) {
// now we iterate over the list children
toArray(list.children).forEach(function(link, index) {
var clickHandler = function(e) {
e.preventDefault(); // prevent navigating anywhere
alert("Hi! I'm a link named '" + link.textContent +
"' and my forEach index is: " + index +
" (" + typeof index + ")");
}
link.onclick = clickHandler;
// now let's use the link list as a mock data source and generate buttons
var newButton = document.createElement('button');
newButton.textContent = link.textContent;
newButton.onclick = clickHandler;
buttonDiv.appendChild(newButton);
});
});
<ul class="link-list">
<li><a href="#">link 1</a></li>
<li><a href="#">link 2</a></li>
<li><a href="#">link 3</a></li>
</ul>
<div id="buttons"></div>
有关 why [].forEach.call is discouraged 的更多详细信息。
现在来说明常见的陷阱是什么:
"use strict";
// we get lists that contain links to parse
var linkLists = document.getElementsByClassName('link-list');
// and one div to store buttons
var buttonDiv = document.getElementById('buttons');
// let's switch the forEach calls to for loops
// variables added for naming sanity
for (var x = 0; x < linkLists.length; x++) {
var children = linkLists[x].children;
for (var y = 0; y < children.length; y++) {
var link = children[y],
index = y;
// everything is fine up to this point
// now as there's no block context that would keep the variable
// values for the handler we'll get the last value it had
var clickHandler = function(e) {
e.preventDefault(); // prevent navigating anywhere
alert("Hi! I'm (possibly) a link named '" + link.textContent +
"' and my for index is: " + index +
" (" + typeof index + ") \n\n :(");
}
link.onclick = clickHandler;
}
}
// now, what few beginners remember is that when there's no block
// context then all of the variables used above are available outside
// let's reuse the buttons div to get all variable values here
buttons.innerHTML = "Variable values after parsing for loops:" +
"<br/>x = " + x +
"<br/>y = " + y +
"<br/>link.textContent = " + link.textContent +
"<br/>index = " + index;
// so now when we click the link the callback function gets
// the variables from above and not from it's block context
// as it would in other programming languages
<ul class="link-list">
<li><a href="#">link 1</a></li>
<li><a href="#">link 2</a></li>
<li><a href="#">link 3</a></li>
</ul>
<div id="buttons"></div>
单击时所有处理程序都引用 z 的当前值。要在定义中使用 z 的值,我建议
通过调用 Function 作为构造函数来创建 onclick 处理程序,并计算正文字符串中 z 的当前值:
newButton.onclick = new Function("launchForm(this, incoming[(10 * (incoming.length / fields)) + "+ z + "], incoming[(48 * (incoming.length / fields)) + " + z + "]);");
或者在创建 onclick 处理程序时将 z 的值保存在按钮对象上:
newButton["data-z"] = z;
newButton.onclick = function() {....};
但在函数体中将对 "z" 的引用替换为 "this['data-z']"。
newButton.onclick = function() {
launchForm(
this,
incoming[(10 * (incoming.length / fields)) + z],
incoming[(48 * (incoming.length / fields)) + z]);
};
因此,当我动态生成其中的 4 个按钮时,这四个按钮中的每一个都将第一个按钮的信息传递到函数 launchForm 中。我怀疑这是因为当变量 z 完成它的 for 语句时它返回到 0。如果是这样的话,而不是 + z 是 + 1 按钮 1 和 + z 是 + 2 按钮 2 它变成 + z 是 + 0对于所有按钮。
我该如何解决这个问题?谢谢
编辑:已添加以响应更多信息请求:
var newButton = document.createElement('button');
newButton.className = 'pure-button pure-button-primary mikeButton';
newButton.innerHTML='Launch Form';
newDiv4.appendChild(newButton);
所以我对这一切都很陌生,所以我可能用错了术语。我理解页面加载后创建的项目被认为是动态的。 --- 虽然我是新手,但我非常有信心问题出在我最初提出的问题上。通过设置警报和测试,我可以看到第一个按钮完全正常工作,并且所有适当的参数都完美传递。只是按钮 2、3 和 4 也会启动按钮 1 启动的内容。 Incoming.length不变,字段不变。与创建 newButton 的第一个实例到第二个实例时唯一不同的是 z。 --- 当我在创建第二个、第三个和第四个按钮后立即设置警报时,它们会准确显示应该传递的参数。但是在创建它们的函数完成后(基于使用 z 作为变量的 for 语句),它们转换回就好像 z 是 0 并使用按钮 1 的参数(因为在按钮 1 的参数中 z 等于 0)。我只是将 + 1、+2、+3 硬编码到代码中而不是 z,但是创建的按钮数量取决于查询。有时 1 个按钮,有时 10 个。所以这真的不是一个选择。
希望对您有所帮助。
ES5 不使用块上下文,而是在函数上下文上运行。这意味着在 for
循环中您必须立即使用索引变量,否则如果您(例如)在回调函数中引用它,您将获得回调执行期间该变量的值。
有多种方法可以解决这个问题,可能最简单的方法是在代码中演示:
"use strict";
// first off, using [].forEach.call has some cons so we should have
// a way to convert a NodeList to an Array
var toArray = function(input) {
var output = [];
// check if we have an array-like object
if (input && typeof input.length === 'undefined') { return; }
for (var i = 0; i < input.length; i++) {
output.push(input[i]);
}
return output;
}
// we get lists that contain links to parse
var linkLists = document.getElementsByClassName('link-list');
// and one div to store buttons
var buttonDiv = document.getElementById('buttons');
// we convert the NodeLists to arrays to get the forEach function
toArray(linkLists).forEach(function(list) {
// now we iterate over the list children
toArray(list.children).forEach(function(link, index) {
var clickHandler = function(e) {
e.preventDefault(); // prevent navigating anywhere
alert("Hi! I'm a link named '" + link.textContent +
"' and my forEach index is: " + index +
" (" + typeof index + ")");
}
link.onclick = clickHandler;
// now let's use the link list as a mock data source and generate buttons
var newButton = document.createElement('button');
newButton.textContent = link.textContent;
newButton.onclick = clickHandler;
buttonDiv.appendChild(newButton);
});
});
<ul class="link-list">
<li><a href="#">link 1</a></li>
<li><a href="#">link 2</a></li>
<li><a href="#">link 3</a></li>
</ul>
<div id="buttons"></div>
有关 why [].forEach.call is discouraged 的更多详细信息。
现在来说明常见的陷阱是什么:
"use strict";
// we get lists that contain links to parse
var linkLists = document.getElementsByClassName('link-list');
// and one div to store buttons
var buttonDiv = document.getElementById('buttons');
// let's switch the forEach calls to for loops
// variables added for naming sanity
for (var x = 0; x < linkLists.length; x++) {
var children = linkLists[x].children;
for (var y = 0; y < children.length; y++) {
var link = children[y],
index = y;
// everything is fine up to this point
// now as there's no block context that would keep the variable
// values for the handler we'll get the last value it had
var clickHandler = function(e) {
e.preventDefault(); // prevent navigating anywhere
alert("Hi! I'm (possibly) a link named '" + link.textContent +
"' and my for index is: " + index +
" (" + typeof index + ") \n\n :(");
}
link.onclick = clickHandler;
}
}
// now, what few beginners remember is that when there's no block
// context then all of the variables used above are available outside
// let's reuse the buttons div to get all variable values here
buttons.innerHTML = "Variable values after parsing for loops:" +
"<br/>x = " + x +
"<br/>y = " + y +
"<br/>link.textContent = " + link.textContent +
"<br/>index = " + index;
// so now when we click the link the callback function gets
// the variables from above and not from it's block context
// as it would in other programming languages
<ul class="link-list">
<li><a href="#">link 1</a></li>
<li><a href="#">link 2</a></li>
<li><a href="#">link 3</a></li>
</ul>
<div id="buttons"></div>
单击时所有处理程序都引用 z 的当前值。要在定义中使用 z 的值,我建议
通过调用 Function 作为构造函数来创建 onclick 处理程序,并计算正文字符串中 z 的当前值:
newButton.onclick = new Function("launchForm(this, incoming[(10 * (incoming.length / fields)) + "+ z + "], incoming[(48 * (incoming.length / fields)) + " + z + "]);");
或者在创建 onclick 处理程序时将 z 的值保存在按钮对象上:
newButton["data-z"] = z; newButton.onclick = function() {....};
但在函数体中将对 "z" 的引用替换为 "this['data-z']"。