转自 http://www.hitoy.org/event-binding-problem-of-dynamically-generated-content.html

由于实际的需要,有时需要往网页中动态的插入HTML内容,并在插入的节点中绑定事件处理函数。我们知道,用Javascript向HTML文档中插入内容,有两种方法,一种是在写HTML代码写入JS,然后插入到文档中;另外一种是通过ajax的方式,从服务器获取数据,然后用js把获取的数据经过处理后插入文档中;两种方法各有特点,本文将分析新插入到文档中的元素的事件绑定问题,并假定新插入的对象不做内联的事件绑定(即不用类似 <a onclick=””>的形式)。所有的示例将会用到jQuery和原生Javascript。

情况一: 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>

注意,以上代码仅针对chrome,实际项目可能会产生兼容性问题。
本人粗见,欢迎拍砖吐槽。

HTML中动态生成内容的事件绑定问题【转载】的更多相关文章

  1. 万能js实现翻页,动态生成内容自动翻页,兼容各种浏览器(已测试)----神器版!

    转--http://www.2cto.com/kf/201402/277535.html 万能js实现翻页,动态生成内容自动翻页,兼容各种浏览器(已测试)----神器版! 2014-02-11     ...

  2. jquery mobile Checkbox动态添加刷新及事件绑定

    jquery mobile Checkbox动态添加刷新及事件绑定 在微信项目中,涉及到一个多选功能.数据来自后台数据库,需要动态加载. 项目结构:微信api+web app.使用jquery mob ...

  3. ASP.NET中Literal控件的使用方法(用于向网页中动态添加内容)

    原文:https://www.jb51.net/article/82855.htm 可以将 Literal 控件用作网页上其他内容的容器.Literal 控件最常用于向网页中动态添加内容.简单的讲,就 ...

  4. IOS系统中使用zepto的live事件绑定不了的一个办法

    IOS系统中使用zepto的live事件绑定不了的一个办法: 对事件对象添加样式:cursor:pointer

  5. JQuery中动态生成元素的绑定事件(坑死宝宝了)

    今天在做项目的时候,遇到了一个前端的问题,坑了我好长时间没有解决,今天就记录于此,也分享给大家. 问题是这样的,首先看看我的界面,有一个初始印象: 下面是操作列所对应的JS代码: { "da ...

  6. 在后台代码中动态生成pivot项并设置EventTrigger和Action的绑定

    最近在做今日头条WP的过程中,遇到需要动态生成Pivot项的问题.第一个版本是把几个频道写死在xaml里了,事件绑定也写在xaml里,每个频道绑定一个ObservableCollection<A ...

  7. js—input框中输入数字,动态生成内容的方法

    项目中需要在前端实现: 用户输入数字n,动态生成n个元素,删除n,自动清空n个元素(如图一): 用户输入数字n,失焦生成n个元素,再聚焦修改n,自动清空n个元素(如图二): 图一: 图二: 需求一实现 ...

  8. html动态生成的代码,绑定事件

    如果使用jQuery,你可以这样写: // .class为你绑定事件的动态生成的结点 $(document).on('click', '.class', function() { // 你要绑定的事件 ...

  9. Jquery中动态生成的元素没有点击事件或者只有一次点击事件

    今天用jq做动态生成的元素的click事件时,click只执行了一次,当然有些朋友可能根本没执行, 执行了一次的原因是因为可能有函数加载了一遍,一次都没执行的可能是没绑定对象或者jq版本问题, 动态生 ...

随机推荐

  1. Tomcat启动错误【Error listenerStart】

    今天启动Tomcat启动不了,报以下错: org.apache.catalina.core.StandardContext startInternal SEVERE: Error listenerSt ...

  2. 每周分享之 二 http协议(2)

    本次分享http协议,共分为三部分,这是第二部分,主要讲解请求与响应的字段,以及状态码. 以http/1.1版本的一个完整的请求与响应作为例子 http请求信息由三部分组成 1.请求方法(GET/PO ...

  3. C# 中函数内定义函数的委托方法

    //定义委托方法Action(无返回值)Func(有返回值) //无返回值委托 Action<string> SetKeyAndValue = delegate(string key) { ...

  4. 使用路由延迟加载 Angular 模块

    使用路由延迟加载 Angular 模块 Angular 非常模块化,模块化的一个非常有用的特性就是模块作为延迟加载点.延迟加载意味着可以在后台加载一个模块和其包含的所有组件等资源.这样 Angular ...

  5. Python实战之实现简单的购物车系统

    #!usr/bin/env Python3 # -*-coding:utf-8-*- # 程序:购物车程序 # # 需求: # # 启动程序后,让用户输入工资,然后打印商品列表 # 允许用户根据商品编 ...

  6. Python自学笔记-字符串编码(来自廖雪峰的官网Python3)

    感觉廖雪峰的官网http://www.liaoxuefeng.com/里面的教程不错,所以学习一下,把需要复习的摘抄一下. 以下内容主要为了自己复习用,详细内容请登录廖雪峰的官网查看.   1.理解变 ...

  7. There is no getter for property named xxx' in 'class java.lang.xxx'

    在xxxMapper.xml我们使用sql片段来提高sql代码的复用性,当时新手传入参数时常常出现这样的错误: There is no getter for property named xxx' i ...

  8. C#微信公众号/订阅号开发 接口源码

    using System; using System.Web; using System.IO; using System.Text; using System.Web.Security; using ...

  9. Linux目录结构详解(一)

    Linux目录结构,在逻辑上所有目录只有一个顶点,即/(根目录),是所有目录的起点.根下面类似于一个倒挂着的树的结构. Linux目录按照类别组织: 应用程序 /usr/bin 数据文件,帮助/usr ...

  10. Echarts数据可视化radar雷达坐标系,开发全解+完美注释

    全栈工程师开发手册 (作者:栾鹏) Echarts数据可视化开发代码注释全解 Echarts数据可视化开发参数配置全解 6大公共组件详解(点击进入): title详解. tooltip详解.toolb ...