js代理监听动态添加元素事件(类似jquery的delegate事件)

来源:互联网 发布:sql数据库修复软件 编辑:程序博客网 时间:2024/05/21 06:40

很多时候我们需要监听动态添加的元素事件。

举个例子:

页面中有一个div,div中有一个button以及一个table,我们需要在点击button的时候相应的table行进行排序,而根据特定需求ajax返回数据中的table值是变化的,

table变化导致了原先的button必须被移除掉,然后在对应业务地方再添加上一个对table进行排序功能的button。换句话说 这个button的功能是不变的,但是这个button是不停的被替换的。

如果我们用传统的dom事件处理,button.on('click',fn),或者button.addEventListener('click',fn,false)只能对当前的button产生作用,一旦该button被替换掉,

即使再生成的button的id跟之前属性一个样,也不会触发这个事件。毕竟已经不是之前那个button了,对应的事件也就不会触发了。

有几种解决办法:

一:添加button后给button继续绑定事件:

    即页面由于某种操作导致原先button被移除掉,在生成新的button时候给该button每次都重新绑定上一个事件,

    例如:生成新button后将button加入文档中后加上:document.getElementById('button').onclick=function(e){fn}

    利用这种方式可以很直观的解决对新建元素的绑定事件,从而也达到了我们对动态生成元素绑定事件一说;

    不过这种方式有个致命缺点:即每次绑定一个事件在卸载这个元素时候,该元素对应的事件没有被消除,即使元素被消除了,其对应的事件没有被删除掉,因为dom1级事件是无法消除掉的,也就是导致了内存不停的增加。

    不过如果换做addEventListener方式去监听,也可以利用removeEventListener去移除掉事件绑定;

    但是在每次生成新元素时候都需要动态的去绑定事件,这点对于模块化开发还是不是那么方便,毕竟一个项目不能是一个人写的代码,如果修改还是要污染源代码的,且维护也不是那么方便

二:jquery中的live或者delegate事件:

    jquery中的事件处理可以说已经做得很好了,而且考虑的特别周到,我们可以很方便的应用delegage去处理当前或者未来创建的元素,

    undelegate事件去监听以及移除相应事件。不明白的可以看看这里;

三:js事件代理:

    之前有一篇文章介绍过js的自定义事件,那篇文章中的js自定义事件是基于事件已经触发,即元素事件已经触发进而继续其他事件。

    其实js事件代理跟那篇文章中的方式有点相似,都是将事件处理放置于一个对象,然后根据自定义属性去取得该事件,对象中的事件可以很方便的去删除调用。先看我的代码实现:

    var _delegateList=[];

    var _getDlgParent=function(ele){

          if(!ele) return null;

          return ele.getAttribute && (!!ele.getAttribute("zip_dlg")) ? ele : arguments.callee(ele.parentNode);

    };

    var  delegate=function (delegate, callback, evt) {

        if (!delegate) return;

        callback = callback || function () { };

        evt = evt || "click";

        var _this = this;

        var fn = function (e) {

            e = window.event || e;

            var target = e.target || e.srcElement,

                attr = target.getAttribute("zip_dlg");

            if (attr && attr == delegate) {

                callback({

                    target: target,

                    event: e

                });

                return;
            }

            //冒泡zip_dlgbubble="true" 

            var isBubble = target.getAttribute("zip_dlgbubble");

            if(isBubble === null) return; 

            target = _getDlgParent(target);

            attr = target.getAttribute("zip_dlg") ; 

            if(target && attr && attr == delegate) {

                callback({

                    target: target,

                    event: e

                });

            }

        };

        _delegateList.push([callback, fn]);

        if(!+"\v1") {

            document.body['e'+type+fn]=fn;

            document.body.attachEvent( 'on'+evt, function() {

                document.body['e'+type+fn]();

            });

        }else{

            document.body.addEventListener( evt, fn, false );

        }

    };

    var undelegate=function (delegate, callback, evt) {

        var fn = null,evt = evt || "click";

        var list = _delegateList, len = list.length;

        for (var i = 0; i < len; i++) {

            if (list[i][0] === callback) {

                fn = list[i][1];

            }

        }

        if (!fn) return;

        if(document.body.removeEventListener){

            document.body.removeEventListener(type,fn,false);

        }else if(document.body.detachEvent){

            document.body.detachEvent('on'+type,fn)

        }else{

            document.body["on"+type]=null

        }

    }

    使用方法:

    假设页面元素<button zip_dlg='dayMonth'></button>

    delegate('dayMonth',fn);

    function fn(e){

      xxx

    }

    其原理就是利用函数加载事件,使得事件一直保存在运行环境中,不管删除添加元素,都会从文档中去寻找对应的元素进而实现事件代理监听

    这样的话只需要加载一次该事件处理程序,在移除button新增button中加入zip_dlg='dayMonth'属性值即可

    并且可以在不需要绑定事件时候可以用undelegate('dayMonth',fn);解除绑定

    并且支持事件冒泡。

    这样就实现了动态元素监听事件,而且不必每次新增元素都新增一个事件,以及内存泄露问题;

    另外,我们还可以利用js的原生的事件代理,根据事件冒泡,在元素父元素上绑定事件 去监听事件处理。例如ul下的li,我们可以将事件绑定到ul上,这样每次处理事件都会先找到ul然后在寻找li。

0 0