我有以下情况,我无法解决。我对js比较新。我有一个在网页上运行的js。按下KB快捷方式时,脚本将运行。在修改了一些内容之后,它会弹出一个html横幅,我想在其中放置某些消息和按钮,具体取决于用户运行脚本的内容。对于一个简单的情况,假设这个弹出窗口中有两个可能的消息。我在对象数组中有详细信息:
NH_Bann = {
STC: {
active: false,
bannText: "Force Title Case: ",
id: "toTitleCaseStrong",
value: "Yes",
action: function() {
var newNameStr = toTitleCaseStrong(vname);
if (newNameStr !== name) {
//**update function
NH_Bann.STC.active = false;
}
}
},
DTC: {
active: false,
bannText: "Enable DTC? ",
id: "addDTC",
value: "Yes",
action: function() {
//**update function
NH_Bann.DTC.active = false;
}
}
}
运行脚本时,有一些if语句可以将活动键更改为true。脚本运行后,我想运行NH_Bann中的对象,如果活动键为true,则发出一条消息,其中包含一个触发操作按钮的操作按钮。我遇到麻烦的部分是动态制作按钮。从其他线程,我以为我可以将按钮存储在一个数组中,但也许onclick不能这样工作?这就是我所拥有的:
function setupButtons() {
var ixButt = 0;
var btn = [];
for (var NHix = 0; NHix < Object.keys(NH_Bann).length; NHix++ ) {
tempKey = Object.keys(NH_Bann)[NHix];
if (NH_Bann[tempKey].active) {
btn[ixButt] = document.getElementById(NH_Bann[tempKey].id);
btn[ixButt].onclick = function(){
NH_Bann[tempKey].action();
assembleBanner(); // makes the html for the banner
}
ixButt++;
}
}
}
我在另一段设置id的代码中创建了按钮:
function assembleBanner() {
sidebarMessageEXT = [sidebarMessage.slice(0)];
var EXTOption = false;
for (var NHix = 0; NHix < Object.keys(NH_Bann).length; NHix++ ) {
tempKey = Object.keys(NH_Bann)[NHix];
if (NH_Bann[tempKey].active) {
sidebarMessageEXT.push(NH_Bann[tempKey].bannText + '<input id="' + NH_Bann[tempKey].id + '" type="button" value="' + NH_Bann[tempKey].value + '">');
EXTOption = true;
}
}
if (EXTOption) {
sidebarMessageEXT = sidebarMessageEXT.join("<li>");
displayBanners(sidebarMessageEXT,severity);
setupButtons();
} else {
displayBanners(sidebarMessage,severity);
setupButtons();
}
}
我遇到的问题是,如果两个对象都处于活动状态== true,我会在横幅中获得两个不同的消息和两个按钮,但是按下它们总会触发DTC对象的更新功能。有什么建议?我对其他方法持开放态度,但我需要能够随着时间的推移添加到对象列表中,并且有条件地在每个对象的活动键的状态上显示按钮。 THX!
答案 0 :(得分:1)
问题与闭包有关。在这段代码中:
function setupButtons() {
var ixButt = 0;
var btn = [];
for (var NHix = 0; NHix < Object.keys(NH_Bann).length; NHix++ ) {
tempKey = Object.keys(NH_Bann)[NHix];
if (NH_Bann[tempKey].active) {
btn[ixButt] = document.getElementById(NH_Bann[tempKey].id);
btn[ixButt].onclick = function(){
NH_Bann[tempKey].action();
assembleBanner(); // makes the html for the banner
}
ixButt++;
}
}
}
... tempKey
是一个存在于setupButtons
调用内的变量。请注意,您在循环中创建了两个onclick
函数回调,并且都引用了tempKey
。但是,它们不会在函数创建时引用变量的值,而是变量的最新值。因此,一旦循环完成,tempKey
将引用它具有的 last 值。
要解决此问题,您可以使用此技巧为每个具有正确值的onclick
创建新闭包:
function setupButtons() {
var ixButt = 0;
var btn = [];
for (var NHix = 0; NHix < Object.keys(NH_Bann).length; NHix++ ) {
tempKey = Object.keys(NH_Bann)[NHix];
if (NH_Bann[tempKey].active) {
btn[ixButt] = document.getElementById(NH_Bann[tempKey].id);
btn[ixButt].onclick = (function(buttonId) {
return function() {
NH_Bann[buttonId].action();
assembleBanner(); // makes the html for the banner
}
})(tempKey);
ixButt++;
}
}
}
本质上,这是将tempKey
的当前值绑定到一个新变量,方法是将它传递给一个立即执行的函数,因此onclick
函数不再引用在循环期间发生变化的变量。
对于一种不那么深奥的方法,你可以将每个按钮的创建移动到它自己的命名函数中,传递所需的数据:
function setupButtons() {
var btn = [];
for (var NHix = 0; NHix < Object.keys(NH_Bann).length; NHix++) {
tempKey = Object.keys(NH_Bann)[NHix];
if (NH_Bann[tempKey].active) {
btn.push(setupButton(NH_Bann[tempKey]);
}
}
}
function setupButton(bannerData) {
var button = document.getElementById(bannerData.id);
button.onclick = function() {
bannerData.action();
assembleBanner();
};
return button;
}