js中两种方式绑定事件的区别你都知道吗?

133 阅读2分钟

相信很多学习前端开发的朋友,应该遇见过页面动态渲染标签时,给这些动态标签绑定事件的时候,会出现绑定事件失效的问题,针对这个问题,作者以下面的两个方法为例,讲解一下怎么解决

动态元素绑定元素的两个方法:

1、利用事件委托

事件委托:事件委托就是通过事件流的特征解决一些开发需求的知识技巧,其原理是利用是事件冒泡的特点,给父元素注册事件,当我们触发子元素时,会冒泡到父元素身上,从而触发父元素的事件,这么做的目的是为了减少事件注册此时,提高开发性能

给动态标签的元素绑定事件,利用事件委托机制加上事件对象 完成 动态标签渲染

测试demo

![测试事件委托demo.gif](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/62d7c17872264116841aec0067f260ba~tplv-k3u1fbpfcp-watermark.image?)
 <body>
     <button>新增</button>
     <ul>
     </ul>
     <script>
         const ul = document.querySelector('ul')
         const arr = ['aaa', 'bbb', 'ccc']
         // 渲染函数
         function render() {
 ​
             ul.innerHTML = arr.reduce((a, b, index) => {
                 const id = Date.now()
                 return a + `<li data-index=${index}>${b}</li>`
             }, '')
         }
         render()
         
         // 点击删除
         //利用事件委托绑定点击事件
         // 注意点: 需要有一个原本已经存在与页面的父元素,这里以ul标签为例
         //为父元素绑定点击事件
         ul.addEventListener('click', function (e) { // e 是事件对象  e.target表示当前选中元素
             if (e.target.tagName === 'LI') {
                 let { index } = e.target.dataset //根据下标删除对应元素
                 arr.splice(index, 1)
                 render()
             }
         })
         // 点击添加按钮添加
         document.querySelector('button').addEventListener('click', function () {
             arr.push('新增元素')
             render()
         })
     </script>
 </body>

2、循环绑定

循环绑定步骤:

需先获取 动态元素dom节点伪类,然后开启循环,给每个元素绑定上事件

存在问题:

当有渲染函数,使用数据驱动视图的编程思想,页面重新渲染之后,页面上的动态元素将被重新 创建 ,但节点的事件并未重新 绑定,所以会导致失效

1、正常删除 demo

删除demo.gif

2、新增后 删除 demo

新增后 删除demo.gif

问题示范

 <body>
     <button>新增</button>
     <ul>
 ​
     </ul>
     <script>
         const ul = document.querySelector('ul')
         const arr = ['aaa', 'bbb']
         // 渲染函数
         function render() {
             ul.innerHTML = arr.reduce((a, b, index) => { return a + `<li data-id=${index}>${b}</li>` }, '')
         }
         render()
 ​
         // 点击删除
         // 获取所有li 
         const liArr = document.querySelectorAll('li')
         //循环绑定点击事件
         liArr.forEach((item, index) => {
             item.addEventListener('click', function () {
                 arr.splice(arr[index], 1) // 点击当前元素 ,删除当前元素
                 render()
             })
 ​
         })
 ​
         // 点击添加按钮添加
         document.querySelector('button').addEventListener('click', function () {
             arr.push('新增元素')
             render()
         })
     </script>
 </body>
解决办法:

1、改为事件委托的方式绑定事件

2、将循环绑定的元素移入渲染函数之内,动态获取dom节点,每当页面重新创建节点之间重新获取,完事动态绑定事件

循环绑定错误示范demo:

正确示范demo

修改后正常demo.gif

解决问题代码

 <body>
     <button>新增</button>
     <ul>
 ​
     </ul>
     <script>
         const ul = document.querySelector('ul')
         const arr = ['aaa', 'bbb']
         // 渲染函数
         function render() {
             ul.innerHTML = arr.reduce((a, b) => a + `<li>${b}</li>`, '')
             //  将删除点击事件 放进渲染函数,点击就重新渲染
             // 点击元素删除
             // 获取所有li 
             const liArr = document.querySelectorAll('li')
             //循环绑定点击事件
             liArr.forEach((item, index) => {
                 item.addEventListener('click', function () {
                     arr.splice(arr[index], 1)// 点击当前元素 ,删除当前元素
                     render()
                 })
 ​
             })
         }
         render()
 ​
         // 点击添加按钮添加
         document.querySelector('button').addEventListener('click', function () {
             arr.push('新增元素')
             render()
         })
     </script>
 </body>

总结:数组循环绑定事件,如果在渲染函数外面,每次执行事件后,渲染函数执行,页面标签重新动态创建到导致 这些标签已经不是原来的标签了,所以绑定的事件失效,所以在渲染函数内,当页面标签重新被创建,立刻获取到最新动态标签的dom元素的列表,重新循环绑定,如此就解决了动态标签失效的问题,但是性能不好,所以我还是推荐大家使用事件委托对动态元素进行事件绑定,简便快捷,性能好,推荐!!!