动态事件绑定

来源:互联网 发布:最好企业网络投资理财 编辑:程序博客网 时间:2024/04/30 12:13

今天项目中有一个问题,就是关于动态生成的HTML标签的事件动态绑定,我原来是直接在动态生成的HTML标签后面,执行this.method();方法是可以绑定了,但原来符合的标签进行的多次方法绑定,所以后面会造成同一个事件的多次运行,所以在这里对这个问题进行总结,(总结是个很好的习惯)引用了一段别人的说明总结:

情况一: HTML代码存放在JS中,请看以下代码:

  • <body>
  • <p>第1行内容</p>
  • <p>第2行内容</p>
  • <p>第3行内容</p>
  • <script>
  • var appendhtml=document.createElement("p");
  • appendhtml.innerHTML="这是插入的内容";
  • document.body.appendChild(appendhtml);
  • var nodep=document.getElementsByTagName("p");
  • for (var i=0;i<nodep.length;i++){
  • nodep[i].onclick=function(){
  • console.log("Click Event!");
  • }
  • }
  • </script>
  • </body>

上面的代码是用原生的Javascript生成的,当此代码执行时,js会在页面中生成第四个P标签,且点击这四个标签的时候,都会触发相应的动作。那么是不是就是说,用js生成的HTML内容,都可以被绑定相应的事件呢?答案是否定的,在上面代码的script标签中,有两个代码段,代码段一是用来向HTML中插入内容的,代码段二是用来绑定事件的,如果把代码段一和代码段二互换位置,发现JS生成的第四个P标签没有绑定上click事件。用以下代码的jquery测试:

  • $(function(){
  • $("p").click(function(){
  • console.log("Click Event");
  • })
  • $("<p>这是生成的内容</p>").appendTo("body");
  • })

发现结果也一样,事件执行成功与否也代码段的顺序有直接的关系。其实原来很好分析,无论是利用getElementsByTagName还是jquery的选择器,当需要的内容还没有被插入时,选择器只会选择页面中已经存在的元素,所以事先没有存在元素是绑定不了事件的。

但是,实际情况是,工作中有可能需要把后来生成的元素绑定上事件,并注册上事件处理函数。例如本网站的留言系统,第一次加载只会显示固定条数的评论,如果评论超过一定数量,剩下的会用ajax的方式进行加载。所有的留言最后都有个回复功能,点击可以恢复相应的留言,也就是说,动态加载上来的留言,也许要绑定click事件,并注册上回复留言的函数。当然偷懒的方法是,为ajax加载上来的内容再注册一个click并再绑定一次相应的函数,但这加大了代码的冗余度,增加系统开销,还会使代码变得难以理解。那么更好的解决办法是什么呢?

留言系统的回复功能

留言系统的回复功能

可以这样理解,无论HTML内容是不是JS生成的,只要没有跨域,所有页面内的元素都属于这个页面,都能够绑定事件,JS中有个非常重要的概念叫事件冒泡,简单来讲,就是子元素产生的事件,会一直冒泡到最顶级父元素,并能够被父元素监测到。请看下图:

事件冒泡

事件冒泡

那么,我能不能在被插入元素的父元素上监测冒泡产生的事件,并回调相应的函数呢?答案是当然是肯定的。来看下面的例子,注意网页面里插入内容是在JS代码的最后。

  • <script>
  • $(function(){
  • $("body").delegate("p","click",function(){
  • console.log("Click Event");
  • })
  • $("<p>这是生成的内容</p>").appendTo("body");
  • })
  • </script>

这是,发现所有的P元素点击都产生了输出,说明代码运行成功。这里我们用到了jQuery的delegate函数,来看一下官方解释:

Attach a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root elements.
根据特定的根元素,把一个或者多个事件注册到指定的元素上,不论这个元素现在是否存在。

在jQuery1.7.3以上的版本中,on方法也可以做这件事,官方有示例说明,这里不再赘述。
jQuery提供一个强大的API来解决这个问题,原生的JS怎么去做呢?下面给出一个简单方案,希望能对大家理解冒泡的原理有所帮助。

  • <script>
  • function gelegate(action,selector,callback){
  • document.addEventListener(action,function(e){
  • if(selector==e.target.tagName.toLowerCase()||selector==e.target.className){
  • console.log("Click Event");
  • callback();
  • }
  • })
  • }
  • gelegate('click','p',function(){});
  • var appendhtml=document.createElement("p");
  • appendhtml.innerHTML="这是插入的内容";
  • document.body.appendChild(appendhtml);
  • </script>
上述能够很好的对动态事件绑定进行原因说明,总结解决这个问题如下:

1,内联法:直接在HTML中调用,如:<input type="button" onclick="doEventThing(event)">   
2,W3C:这个比较通用,因为是标准,如document.getElementById("div_1").addEventListener("click",function(){alert(this.id);},false);

3,上面说的一种方法,觉得也不错,通过事件冒泡,在被插入元素的父元素上监测冒泡产生的事件,并回调相应的函数。

总结如上,在此说明:<input type="button" onclick="doEventThing(event)">  ,在doEventThing(event)方法中,this表示window对象,表示当前作用域对象的话,应该直接传this,例如doEventThing(this)


0 0