在JS中如何实现动态添加元素
这篇文章主要给大家介绍了关于JS动态添加元素及绑定事件造成程序重复执行的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
前言
本文主要给大家分享一下前段时间遇到的bug,这个Bug是关于jquery 的on方法绑交互事件,类似于$('#point').on('click','.read-more',function () {})
这样的代码造成的程序重复执行,很多人在文章里写到了,也说了用off方法来解绑,但都未能点出问题的本质,几乎都忽略了问题的本质其实是事件委托造成的。
话不多说,上点天天看到的代码:
第一种:
$(document).on('click', function (e) { consol.log('jquery事件绑定') });
第二种:
document.addEventListener('click',function (e) { consol.log('原生事件绑定') });
第三种:
var id = setInterval(function () { console.log('定时器循环事件绑定') },1000);
上面的代码,相信不少同盟,天天都会写到,看似简单的事件绑定,却经常能给我们带来意想不到的结果,特别是在这个SPA,应用AJAX页面局部刷新如此盛行的时代。
那什么是事件绑定,造成的程序重复执行呢?这个事情要说清除,好像不是那么简单,还是用一段测试代码来说明吧。你可以拷贝到本地,自己试试:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button class="add_but">点击</button> <p id="point">fdfsdf </p> <script src="https://cdn.bootcss.com/jquery/1.8.3/jquery.js"></script> <script> var count=1; var example = { getData:function () { var data ={ content:'df'+count++, href:'' }; this.renderData(data); }, renderData:function (data) { document.getElementById('point').innerHTML='<p>this is a '+data.content+'点此<a class="read-more" href="javasript:;" rel="external nofollow" rel="external nofollow" >查看更多</a></p>'; $('#point').on('click','.read-more',function () { alert('事故发生点'); }) /* setInterval(function () { console.log('fdfdfg'); },2000);*/ /*用冒泡来绑定事件,类似于Jquery的on绑定事件*/ /* document.querySelector('body').addEventListener('click',function (e) { if(e.target.classList.contains('read-more')){ alert('事故发生点'); } })*/ } } ; document.querySelector('.add_but').addEventListener('click',function (e) { example.getData(); e.stopImmediatePropagation(); }); </script> </body> </html>
以上是我为说清这个事情写的一段测试代码,可以拷贝下来试试。当我们点击页面的按钮,触发调用example.getData()
这个函数,模拟ajax获取数据成功后,就会根据局部刷新页面内元素类名为point的内容,同时会为加载这个内容中的read-more A标签绑定一个事件,就这样我们想要的效果出现啦,当元素第一次加载时,页面正常,‘事故发生点'弹出一次,当二次刷新触发后,你会发现其弹出了两次,当第三次时,你会发现,其弹三次,以此类推。。。。
OMG,这个程序到底怎么了,我明明每次事件绑定前,前面绑定的元素都删除了,为什么,被删除的尸体感觉还在动作,好吧,上面就是我第一次遇到这个情况发出的感叹。
最后是问身边的大神,才突然领悟,原来绑定一直都在,而这个绑定被保存在一个叫做事件队列的地方,他不在循环执行的主线程中,画了一张需要默契才能看懂的图,勉强看一看。
事件队列
还原真相
其实上面那一段代码是为了测试而特意写的代码,除了定时器外,其他两个点击事件换个正常的写法,重复执行的情况是不会出现的,正常的代码:
// jquery 事件直接绑定的写法; $('#point .read-more').on('click',function () { alert('事故发生点'); }) // 原生JS 事件直接绑定的写法; document.querySelector('.read-more').addEventListener('click',function (e) { alert('事故发生点'); })
看出差别了吗?其实就是不用冒泡来事件委托,而是直接给添加的元素绑定事件。所以Dom事件是讲道理的,动态添加的元素,再动态为此绑定事件,待元素被删除后,与其绑定的相应事件其实是会从事件绑定队列中删除的,而非如上面测试代码,给人的感觉是元素移除后,但其绑定的事件还在内存中。但请记住,这是个误会,上面测试的代码之所以给人这种错觉,是因为我们并没有为动态添加的元素绑定事件,而仅仅是用了事件委托的形式,实际上事件是绑定在#point元素上的,其一直存在,利用事件冒泡来让程序知道我们点击了动态添加的链接元素。测试中特意用原生js去重现了这次事件委托,jquery的on绑定事件其实原理基本相同。
document.querySelector('body').addEventListener('click',function (e) { if(e.target.classList.contains('read-more')){ alert('事故发生点'); } })
解除bug的那些方法
定时器
这个是最易犯的错误,当然也是最易解的错误,因为设定定时器时,其会返回一个数值,这个数值应该是事件队列此定时器中的一个编号吧,类似于9527;步骤就是设定一个全局变量来保持这个返回值id,在每次设定定时器时,先通过id清除已经设定过的定时器
clearInterval(intervalId); //粗暴的写法 intervalId&&clearInterval(intervalId); //严谨的写法 intervalId=setInterval(function () { console.log('fdfdfg'); },2000);
Dom事件
其实上面我们已经说过,最直接的办法就是不采用事件委托,而是采用直接绑定;如果确实要用事件委托来绑定事件,那就是解绑。在jquery中提供了unbind函数来解绑事件,不过在jquery 1.8版本以后,这个方法已经不推荐了,而是推荐off方法。比如上面的on事件委托的方式,要解绑,可采用语句$('#point').off('click','.read-more')
。
有缺陷的解决方案,添加flag
很好理解,第一次绑定后,flag置位,下一次在执行这个绑定时,程序就知道在这个节点上已经有了绑定,无需再添加,具体操作就是:
var flag = false; var example = { getData: function () { var data = { content: 'df' + count++, href: '' }; this.renderData(data); }, renderData: function (data) { document.getElementById('point').innerHTML = '<p>this is a ' + data.content + '点此<a class="read-more" href="javasript:;" rel="external nofollow" rel="external nofollow" >查看更多</a></p>'; !flag && $('#point').on('click', '.read-more', function () { alert('事故发生点'+data.content); }); flag = true; } };
从逻辑上,看起来没有问题,但仔细观察,发现这是有问题的。当我们第二次,第三次刷新时,弹出框的内容还是和第一次模拟刷新后点击后弹出的内容一致,还是'事故发生点df1',而非和内容一样递增,为什么呢,感觉事件队列里面的回调函数被单独保存起来了,data被深拷贝了,而不再是一个引用。确实有点难理解,我也不知道到底是为什么,如果哪位能说清楚,还请一定告知。
结个尾写在最后,其实平常写一些程序时,事件绑定,造成程序重复执行这些情况很少发生,其通常会出现在我们写插件的时候,插件需要适应多种调用环境,所以在插件内部做到防止事件重复绑定的情况非常重要。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
以上是在JS中如何实现动态添加元素的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

如何使用JS和百度地图实现地图平移功能百度地图是一款广泛使用的地图服务平台,在Web开发中经常用于展示地理信息、定位等功能。本文将介绍如何使用JS和百度地图API实现地图平移功能,并提供具体的代码示例。一、准备工作使用百度地图API前,首先需要在百度地图开放平台(http://lbsyun.baidu.com/)上申请一个开发者账号,并创建一个应用。创建完成

人脸检测识别技术已经是一个比较成熟且应用广泛的技术。而目前最为广泛的互联网应用语言非JS莫属,在Web前端实现人脸检测识别相比后端的人脸识别有优势也有弱势。优势包括减少网络交互、实时识别,大大缩短了用户等待时间,提高了用户体验;弱势是:受到模型大小限制,其中准确率也有限。如何在web端使用js实现人脸检测呢?为了实现Web端人脸识别,需要熟悉相关的编程语言和技术,如JavaScript、HTML、CSS、WebRTC等。同时还需要掌握相关的计算机视觉和人工智能技术。值得注意的是,由于Web端的计

股票分析必备工具:学习PHP和JS绘制蜡烛图的步骤,需要具体代码示例随着互联网和科技的快速发展,股票交易已经成为许多投资者的重要途径之一。而股票分析是投资者决策的重要一环,其中蜡烛图被广泛应用于技术分析中。学习如何使用PHP和JS绘制蜡烛图将为投资者提供更多直观的信息,帮助他们更好地做出决策。蜡烛图是一种以蜡烛形状来展示股票价格的技术图表。它展示了股票价格的

如何使用PHP和JS创建股票蜡烛图股票蜡烛图是股票市场中常见的一种技术分析图形,通过绘制股票的开盘价、收盘价、最高价和最低价等数据,帮助投资者更直观地了解股票的价格波动情况。本文将教你如何使用PHP和JS创建股票蜡烛图,并附上具体的代码示例。一、准备工作在开始之前,我们需要准备以下环境:1.一台运行PHP的服务器2.一个支持HTML5和Canvas的浏览器3

如何使用JS和百度地图实现地图热力图功能简介:随着互联网和移动设备的迅速发展,地图成为了一种普遍的应用场景。而热力图作为一种可视化的展示方式,能够帮助我们更直观地了解数据的分布情况。本文将介绍如何使用JS和百度地图API来实现地图热力图的功能,并提供具体的代码示例。准备工作:在开始之前,你需要准备以下事项:一个百度开发者账号,并创建一个应用,获取到相应的AP

如何使用JS和百度地图实现地图点击事件处理功能概述:在Web开发中,经常需要使用地图功能来展示地理位置和地理信息。而地图上的点击事件处理是地图功能中常用且重要的一部分。本文将介绍如何使用JS和百度地图API来实现地图的点击事件处理功能,并给出具体的代码示例。步骤:导入百度地图的API文件首先,要在HTML文件中导入百度地图API的文件,可以通过以下代码实现:

随着互联网金融的迅速发展,股票投资已经成为了越来越多人的选择。而在股票交易中,蜡烛图是一种常用的技术分析方法,它能够显示股票价格的变化趋势,帮助投资者做出更加精准的决策。本文将通过介绍PHP和JS的开发技巧,带领读者了解如何绘制股票蜡烛图,并提供具体的代码示例。一、了解股票蜡烛图在介绍如何绘制股票蜡烛图之前,我们首先需要了解一下什么是蜡烛图。蜡烛图是由日本人

如何使用JS和百度地图实现地图多边形绘制功能在现代网页开发中,地图应用已经成为常见的功能之一。而地图上绘制多边形,可以帮助我们将特定区域进行标记,方便用户进行查看和分析。本文将介绍如何使用JS和百度地图API实现地图多边形绘制功能,并提供具体的代码示例。首先,我们需要引入百度地图API。可以利用以下代码在HTML文件中导入百度地图API的JavaScript
