相信很多学习前端开发的朋友,应该遇见过页面动态渲染标签时,给这些动态标签绑定事件的时候,会出现绑定事件失效的问题,针对这个问题,作者以下面的两个方法为例,讲解一下怎么解决
动态元素绑定元素的两个方法:
1、利用事件委托
事件委托:事件委托就是通过事件流的特征解决一些开发需求的知识技巧,其原理是利用是事件冒泡的特点,给父元素注册事件,当我们触发子元素时,会冒泡到父元素身上,从而触发父元素的事件,这么做的目的是为了减少事件注册此时,提高开发性能
给动态标签的元素绑定事件,利用事件委托机制加上事件对象 完成 动态标签渲染
测试demo
 <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
2、新增后 删除 demo
问题示范
<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
解决问题代码
<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元素的列表,重新循环绑定,如此就解决了动态标签失效的问题,但是性能不好,所以我还是推荐大家使用事件委托对动态元素进行事件绑定,简便快捷,性能好,推荐!!!