我已经编写了一个代码来为div容器创建模态窗口。单击按钮后,我会得到按钮的编号并显示相关的模态窗口。经过测试,适用于所有浏览器。
myModalContent = new tingle.modal();
var myBtn = document.querySelectorAll("button.project__btn");
for (var i = 0; i < myBtn.length; i++) {
myBtn[i].addEventListener("click", function () {
myModalContent.open();
if (this.hasAttribute("data-btn")) {
myModalContent.setContent(document.querySelector(".project" + this.getAttribute("data-btn") + "-modal").innerHTML);
} else {
myModalContent.setContent(document.querySelector(".project1-modal").innerHTML);
}
});
} 一个js验证器给出一个警告“不要在循环中创建函数”。 阅读一些与此主题相关的帖子,特别是必须在循环外创建函数,我创建了一个函数:
function handler(modalDiv, trigBtn, index){
modalDiv.open();
if (trigBtn[index].hasAttribute("data-btn")) {
modalDiv.setContent(document.querySelector(".project" + trigBtn[index].getAttribute("data-btn") + "-modal").innerHTML);
} else {
modalDiv.setContent(document.querySelector(".project1-modal").innerHTML);
}
}
然后从循环中调用它:
for (var i = 0; i < myBtn.length; i++) {
myBtn[i].onclick = handler(myModalContent, myBtn, i);
}
它似乎无法正常工作,它会在网页加载后立即显示最后一个模态窗口。我的理解是该函数必须与click事件监听器连接,即当单击一个按钮时,应弹出模态窗口。现在,模式窗口弹出而没有任何点击事件。你能告诉我如何正确编写函数吗?或者,如果我只是简单地忽略这个js验证警告。
答案 0 :(得分:3)
保持简单!您不必更改代码的任何内容,只需将函数表达式移动到循环体外部的命名函数声明:
var myModalContent = new tingle.modal();
var myBtn = document.querySelectorAll("button.project__btn");
function myHandler() {
myModalContent.open();
if (this.hasAttribute("data-btn")) {
myModalContent.setContent(document.querySelector(".project" + this.getAttribute("data-btn") + "-modal").innerHTML);
} else {
myModalContent.setContent(document.querySelector(".project1-modal").innerHTML);
}
}
for (var i = 0; i < myBtn.length; i++) {
myBtn[i].addEventListener("click", myHandler);
}
答案 1 :(得分:2)
该警告试图阻止&#34;修改后的闭包问题&#34;。如果您的函数对变量i
执行了任何操作,那么您发现用户单击按钮时变量i
的值始终为myBtn.length
,因为&# 39; s它在循环结束时结束的值。
此:
for (var i = 0; i < myBtn.length; i++) {
...
这样对待:
var i;
for (i = 0; i < myBtn.length; i++) {
...
由于您未在功能中的任何位置使用i
,因此您在技术上是安全的,但未来其他开发人员可能会更改代码并最终运行这个问题。
为了按照您尝试修复此代码的方式修复此代码,您需要让handler
函数返回一个函数本身。
myBtn[i].addEventListener("click", createHandler());
function createHandler() {
return function() {
myModalContent.open();
if (this.hasAttribute("data-btn")) {
myModalContent.setContent(document.querySelector(".project" + this.getAttribute("data-btn") + "-modal").innerHTML);
} else {
myModalContent.setContent(document.querySelector(".project1-modal").innerHTML);
}
};
}
这与您的工作代码具有相同的效果,但可以阻止某人尝试在闭包内使用i
。如果有人在那里需要i
,他们可以将其添加到createHandler
的参数列表中,在该列表中,每次通过循环时都不会重复使用相同的变量。
或者,如果您可以使用现代版本的javascript,则可以使用let
关键字代替var
。
此:
for (let i = 0; i < myBtn.length; i++) {
...
更像是这个代码在C#:
之类的语言中如何工作for (var _ = 0; _ < myBtn.length; _++) {
var i = _;
...
换句话说,i
变量的范围是for
循环的内部,而不是您所处的函数的全局。