事件委托
就是事件目标自身不处理事件,而是把处理任务委托给其父元素或者祖先元素,甚至根元素(document)。
原理:
事件委托是利用事件的冒泡原理来实现的 。事件监听器会分析从子元素冒泡上来的事件,找到是哪个子元素的事件。
————————————————
比较早的jq写的,没有ES6模板字符串,就js拼接字符串。
大概有个类似这样的需求
- 点击左边
+
号右边添加,再点击,取消灰色并移除右边的菜单项; - 左边添加后,也可以通过右边的
x
来删除,同时移除左边菜单块灰色。
左边就是拿到数据,拼接DOM
元素,放进去,这是就用到了事件委托
,通过子节点元素绑定事件来传递给父元素DOM节点,父元素代子元素执行事件,来统一管理其全部后代子元素。
tips:
对应标签绑定事件这样很不推荐,原因如下(参考忘了)
- 绑定事件太多,浏览器占用内存变大,严重影响性能;
- Ajax出现,局部刷新盛行,每次加载完,都要重新绑定事件;
- 部分浏览器移除元素时,绑定的事件没有被及时移除,导致内存泄漏,严重影响性能;
- Ajax中重复绑定,导致代码耦合性过大,影响后期维护
// 左侧选择添加菜单的方法
function clickPlus(obj) {
$(obj).parent().toggleClass('gray')
var name = $(obj).parent().attr('data-name')
if ($(obj).parent().hasClass('gray')) {
var html = ''
html += '<div class="cont-item" data-name=' + name + '>'
html += '<span class="name">' + name + '</span>'
html += '<span class="delete">x</span>'
html += '</div>'
$('.content').append(html)
} else {
deleteItem(name)
}
}
<div class="submit" onclick="submit(this)"></div>
在.html
文件中可以直接传this
指向的是当前标签,所以,
刚开始想在span
上绑定onclick
把name和this都传过去,这样当前知道选择的元素就可以直接remove()
掉了,如下
html += '<span class="plus" onclick="clickPlus(this,\''+item.name+'\')">+</span>'
但参数多的话容易出问题,还影响性能等等,就转为事件委托,避免此种情况
// 右边直接点击删除按钮
$('.content').on('click', $('.cont-item'), function (ev) {
var delName = $(ev.target).parent().attr('data-name')
var menuArr = $('.right-item .bar')
$.each(menuArr, function (index, item) {
if (delName == $(item).attr('data-name')) $(item).toggleClass('gray')
})
$(ev.target).parent().remove()
})
remove时如果出错,可加一层判断
if($(ev.target).prop('nodeName')=="SPAN") ...remove()
假如.on
那一行改成
//会自动找.cont-item,不需要加$符号指定,这样也就不用判断nodeName这样更常见
$('.content').on('click', '.cont-item', function (ev) {
比起bind、delegate
使用on
更推荐,
$('父元素').on('click', $('子元素'),function(ev){...})
原生js例子:
<ul id = "lists">
<li>列表1</li>
<li>列表2</li>
<li>列表3</li>
<li>列表4</li>
<li>列表5</li>
<li>列表6</li>
</ul>
var lists = document.getElementById("lists");
lists.addEventListener("click",function(event){
var target = event.target;
//防止父元素ul也触发事件
if(target.nodeName == "LI"){
target.style.backgroundColor = "red";
}
})