在JavaScript闭包上遇到困难

时间:2016-11-04 09:27:07

标签: javascript closures

我为菜单切换编写了一些JavaScript,现在我想将它重用于多个元素,并且我正在努力创建一个闭包以正确的方式执行此操作。

现在效果仅限于最后注册的元素,因为设置选项的范围等。



var selectGroup = (function () {

    var defaults = {
        element: document.getElementById('form-select'),
    };

    var setup = {
        open: false
    };
    var opt = {};

    self.init = function (options) {
        opt = options || defaults;
        opt.element = options.element || defaults.element;
        setup.navButton = opt.element.getElementsByClassName('nav-button')[0];
        setup.ulTag = opt.element.getElementsByTagName('ul')[0];
        setup.buttonArrow = opt.element.getElementsByTagName('span')[1];
        registerEvents();
    };


    registerEvents = function () {
        opt.element.onclick = function () {
            if (setup.open) {
                setup.buttonArrow.setAttribute('class', 'expand-arrow');
                setup.ulTag.setAttribute("style", 'max-height:0;');
            } else {
                setup.buttonArrow.setAttribute('class', 'contract-arrow');
                setup.ulTag.setAttribute("style", 'max-height:600px;');
            }
            /*Toggle*/
            setup.open = !setup.open;
        }
    };

    return self;
})();

selectGroup.init({element: document.getElementById('person-nav')});
selectGroup.init({element: document.getElementById('situation-nav')});
selectGroup.init({element: document.getElementById('region-nav')});




2 个答案:

答案 0 :(得分:0)

这不是一个关闭问题,你总是用最新的元素覆盖你的opt.element,这就是为什么只有最后一个元素有效。

您应该使用唯一ID将数据保存在opts中。

这是一个超级简单标记(丑陋)的工作示例:https://jsfiddle.net/cone0oof/2/

答案 1 :(得分:0)

解决方案是删除闭包,使用局部作用域变量并将它们作为参数传递,因为您希望为每个不同的元素创建它们。

下面与原始代码大致相同。 我用内联注释标记了我的更改。

var selectGroup = (function () {

    var defaults = {
        element: document.getElementById('form-select'),
    };

    self.init = function (options) {
        var setup = {   //make it local inside init()
            open: false
        };
        var opt = {};   //make it local inside init()

        opt = options || defaults;
        opt.element = options.element || defaults.element;
        setup.navButton = opt.element.getElementsByClassName('nav-button')[0];
        setup.ulTag = opt.element.getElementsByTagName('ul')[0];
        setup.buttonArrow = opt.element.getElementsByTagName('span')[1];
        registerEvents(opt, setup);  //pass them as parameters
    };


    registerEvents = function (opt, setup) { //receive the parameters
        opt.element.onclick = function () {
            if (setup.open) {
                setup.buttonArrow.setAttribute('class', 'expand-arrow');
                setup.ulTag.setAttribute("style", 'max-height:0;');
            } else {
                setup.buttonArrow.setAttribute('class', 'contract-arrow');
                setup.ulTag.setAttribute("style", 'max-height:600px;');
            }
            /*Toggle*/
            setup.open = !setup.open;
        }
    };

    return self;
})();

selectGroup.init({element: document.getElementById('person-nav')});
selectGroup.init({element: document.getElementById('situation-nav')});
selectGroup.init({element: document.getElementById('region-nav')});