基于对象状态动态创建js / html中的按钮

时间:2015-11-17 02:37:18

标签: javascript html

我有以下情况,我无法解决。我对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!

1 个答案:

答案 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;
}