为所有先前实例设置实例的Javascript类事件

时间:2015-11-01 01:16:25

标签: javascript class events javascript-events

我有一个为每个LI创建mousedown监听器的类。但是,单击第一个实例的LI会导致为其后创建的每个LI实例触发事件。如果你创建了第3个实例,点击第1个实例将导致所有3个点火,点击第2个结果进行第2次和第3次点火等。

要复制,请运行jsfiddle并单击两个链接(一个接一个),这将创建两个UL元素,每个元素包含一个LI元素。警报()设置为显示每个事件触发。如果您继续单击链接,您将看到事件如何继续堆叠。

我刚接触在javascript中创建类,所以我显然错过了一些内容,但无法理解为什么多个实例的事件不是分开的。如果您想知道,我已经按照允许静态变量和方法的方式创建了我的类。我没有使用jQuery。

我已发布a jsfiddle of the below code

更新 修复因为削减SO的复杂代码而导致的错误。我已经更新以反映在每个UL中创建的多个LI元素(该数字是动态的和数据库驱动的)并且ID是唯一的。

<div id="outer">
    <a href="#" onclick="edit('g123')">Click here first id=g123</a>
    <br> 
    <a href="#" onclick="edit('g234')">Click here second id=g234</a>
</div>    

<script>

listbox = (function (id) {
        var currentul = "";
        var counter = 0;

        function listbox(id) {
            this.id = id;
        };

        // show or hide once all the properties are set
        listbox.prototype.go = function () {
            this.initlistbox();
            this.addlisteners();
        }

        // create the elements for drag and drop between two list boxes
        listbox.prototype.initlistbox = function () {
            var _this = this;
            var divlist = document.createElement('div');
            divlist.style.minHeight = '100px';
            divlist.style.width = '300px'
            divlist.style.outline = '1px solid blue'

            // the UL
            var ul = document.createElement('ul');
            ul.setAttribute('id', 'ulchosen-' + this.id);

            // track which UL is active for keystrokes
            ul.addEventListener('click', function (e) {
                if (e.stopPropagation) e.stopPropagation();
                currentul = this.id;
            }, false);

            // add the ul to the div
            divlist.appendChild(ul);

            divouter = document.getElementById("outer");
            // add the div to the body
            divouter.appendChild(divlist);

            // The LI
            // create LI elements
            for (i=0; i < 4; i++){
                var li = document.createElement('li');
                counter++;
                li.setAttribute('id', 'lb-li-chosen-' + counter);
                li.innerHTML = "Hello " + counter + " " + this.id;
                ul.appendChild(li);
            }    
        };

        listbox.prototype.addlisteners = function () {
            var _this = this;

            var lis = document.querySelectorAll("[id^='lb-li-']");
            for (var i = 0; i < lis.length; i++) {
                this.setlilisteners(lis[i]);
            }
        };

        listbox.prototype.setlilisteners = function (el) {
            var _this = this;

            // click is for non drag, non shift / ctrl
            el.addEventListener('click', function (e) {
                alert("A: " + _this.id);
                e.preventDefault();
                return false;
            }, false);

            // mousedown is to select LI elements
            el.addEventListener('mousedown', function (e) {
                e.stopPropagation();
                e.preventDefault();
                alert("B: " + _this.id);
                return false;
            }, false);

        };

        return listbox;
    })();

    function edit(id) {
        var a = new listbox(id);
        a.go();
    } 
</script>

3 个答案:

答案 0 :(得分:1)

每次使用addEventListener时,都会堆叠新功能以供执行。 addEventListener不会删除旧功能。所以你必须每个元素只调用一次。

以下代码可以使用。

listbox = (function (id) {
    var currentul = "";

    function listbox(id) {
        this.id = id;
    };

    // show or hide once all the properties are set
    listbox.prototype.go = function () {
        this.initlistbox();
    }

    // create the elements for drag and drop between two list boxes
    listbox.prototype.initlistbox = function () {
        var _this = this;
        var divlist = document.createElement('div');
        divlist.style.minHeight = '100px';
        divlist.style.width = '300px'
        divlist.style.outline = '1px solid blue'

        // the UL
        var ul = document.createElement('ul');
        ul.setAttribute('id', 'ulchosen-' + this.id);

        // track which UL is active for keystrokes
        ul.addEventListener('click', function (e) {
            if (e.stopPropagation) e.stopPropagation();
            currentul = this.id;
        }, false);

        // add the ul to the div
        divlist.appendChild(ul);

        divouter = document.getElementById("outer");
        // add the div to the body
        divouter.appendChild(divlist);

        // The LI
        // create LI elements
        var li = document.createElement('li');
        li.setAttribute('id', 'lb-li-chosen-1');
        li.innerHTML = "Hello " + this.id;
        ul.appendChild(li);

        this.setlilisteners(li);

    };

    listbox.prototype.setlilisteners = function (el) {
        var _this = this;

        // click is for non drag, non shift / ctrl
        el.addEventListener('click', function (e) {
            alert("A: " + _this.id);
            e.preventDefault();
            return false;
        }, false);

        // mousedown is to select LI elements
        el.addEventListener('mousedown', function (e) {
            e.stopPropagation();
            e.preventDefault();
            alert("B: " + _this.id);
            return false;
        }, false);

    };

    return listbox;
})();

function edit(id) {
    var a = new listbox(id);
    a.go();
}

答案 1 :(得分:1)

Gustavo的回答帮助我找到了这个bug。我没有过滤LI元素只包含当前的UL,因此每增加一个实例,都会再次设置所有LI元素的监听器。他试图告诉我这个......所以这就是:

   listbox.prototype.addlisteners = function () {
        var _this = this;

        var lis = document.querySelectorAll("[id^='lb-li-']");
        for (var i = 0; i < lis.length; i++) {
            // THIS IF STATEMENT WAS MISSING
            if (lis[i].parentNode.id.indexOf("-" + this.id) !== -1){
                this.setlilisteners(lis[i]);
            }
        }
    };

答案 2 :(得分:0)

小提琴正在创建具有相同标识lb-li-chosen-1的多个LI元素,这是无效的HTML。在某些浏览器中,我认为它可能导致查询选择器返回多个LI元素的数组,结果是每次调用.addListeners时,新的事件侦听器函数被添加到目前为止定义的每个LI元素。

相关问题