如何在Javascript中使用onclick按钮函数更改全局变量的值



我是这个平台的新手,刚刚遇到这样一个问题:我想制作一个9x9按钮网格,这样当用户点击坐标为(x,y(的按钮时,x和y的值就会保存到两个全局变量中。以下是我的代码:

然而,当我测试它时,无论我点击哪里,clicked_row和clicked_col的值都将始终为9和9。我认为这是因为函数只使两个值等于I和j,并且它们的值在for循环中停止在9。有没有办法将值i和j传递到函数中?非常感谢。

for (var i = 0; i < 9; i++) {
for (var j = 0; j < 9; j++) {
let btn = document.createElement("button");
btn.innerHTML = ("(").concat((i + 1).toString(), ", ", (j + 1).toString(), ")"); //(i, j)
btn.className = "button";
btn.onclick = function() {
clicked_row = i;
clicked_col = j;
};
document.body.appendChild(btn);
}
document.body.appendChild(document.createElement("BR"));
}

问题是ij变量由所有function()共享,因此它们都得到这些变量的最终值,即9

保存当前值的传统(ECMAScript 4(方法是使用一个函数,将ij的当前值传递到该函数中:

for (var i = 0; i < 9; i++) {
for (var j = 0; j < 9; j++) {
let btn = document.createElement("button");
btn.innerHTML = ("(").concat((i + 1).toString(), ", ", (j + 1).toString(), ")"); //(i, j)
btn.className = "button";
btn.onclick = function(i, j) {
return function() {
clicked_row = i;
clicked_col = j;
};
}(i, j);
document.body.appendChild(btn);
}
document.body.appendChild(document.createElement("BR"));
}

但是您使用的是let,它提供了一种更简单的方法:使用let来定义变量的本地副本(在循环的每次迭代中都是不同的变量(:

for (var i = 0; i < 9; i++) {
for (var j = 0; j < 9; j++) {
let iNow = i, jNow = j;
let btn = document.createElement("button");
btn.innerHTML = ("(").concat((i + 1).toString(), ", ", (j + 1).toString(), ")"); //(i, j)
btn.className = "button";
btn.onclick = function() {
clicked_row = iNow;
clicked_col = jNow;
};
document.body.appendChild(btn);
}
document.body.appendChild(document.createElement("BR"));
}

但在for循环的情况下,JavaScript提供了这方面的简写:

for (let i = 0; i < 9; i++) {
for (let j = 0; j < 9; j++) {
let btn = document.createElement("button");
btn.innerHTML = ("(").concat((i + 1).toString(), ", ", (j + 1).toString(), ")"); //(i, j)
btn.className = "button";
btn.onclick = function() {
clicked_row = i;
clicked_col = j;
};
document.body.appendChild(btn);
}
document.body.appendChild(document.createElement("BR"));
}

与原始代码的唯一区别是将var更改为let。请参阅What';s使用";设";以及";var";?

它被称为闭包

这里有一个简单的解决方案,不需要一个

如果使用数据属性,则可以将列和行存储在那里。

或者显示文本内容,或者像我的第二个例子一样在循环中使用let

for (let i = 1; i < 10; i++) {   // these lets also help
for (let j = 1; j < 10; j++) { // avoiding having to create a closure 
let btn = document.createElement("button");
btn.innerHTML = ("(").concat((i).toString(), ", ", (j).toString(), ")"); //(i, j)
btn.className = "button";
btn.dataset.clicked_row = i;
btn.dataset.clicked_col = j;
btn.onclick = function() {
console.log(this.dataset.clicked_row,this.dataset.clicked_col)
};
document.body.appendChild(btn);
}
document.body.appendChild(document.createElement("BR"));
}

该代码将显示在循环中使用let也消除了对闭包的需要

for (let i = 1; i < 10; i++) {
for (let j = 1; j < 10; j++) {
let btn = document.createElement("button");
btn.innerHTML = ("(").concat((i).toString(), ", ", (j).toString(), ")"); //(i, j)
btn.className = "button";
btn.onclick = function() {
let clicked_row = i;
let clicked_col = j;
console.log(clicked_row,clicked_col)
};
document.body.appendChild(btn);
}
document.body.appendChild(document.createElement("BR"));
}

由于您使用的是var,因此需要将该函数封装在闭包中,以使i的值与名为i的变量不同。

for (var i = 0; i < 9; i++) {
for (var j = 0; j < 9; j++) {
let btn = document.createElement("button");
btn.innerHTML = ("(").concat((i + 1).toString(), ", ", (j + 1).toString(), ")"); //(i, j)
btn.className = "button";
btn.onclick = (function(i, j) {
return function() {
clicked_row = i;
clicked_col = j;
console.log({clicked_row, clicked_col});
};
})(i, j);
document.body.appendChild(btn);
}
document.body.appendChild(document.createElement("BR"));
}

如果您希望左上角为(1, 1),请使用以下内容:

for (var i = 1; i <= 9; i++) {
for (var j = 1; j <= 9; j++) {
let btn = document.createElement("button");
btn.innerHTML = ("(").concat((i).toString(), ", ", (j).toString(), ")"); //(i, j)
btn.className = "button";
btn.onclick = (function(i, j) {
return function() {
clicked_row = i;
clicked_col = j;
console.log({clicked_row, clicked_col});
};
})(i, j);
document.body.appendChild(btn);
}
document.body.appendChild(document.createElement("BR"));
}

最新更新