事件冒泡应用:事件代理
文章目录
1. 什么是事件代理
事件代理,应用了事件冒泡的特性,将一个元素的事件处理,交给祖先元素进行处理。即,自己本身不处理事件,而是通过冒泡的特性,触发祖先元素的相同事件,调用祖先元素的回调函数。
2. 事件代理的实现
回看之前为了总结知识,做的一个小练习*点击查看→示例代码:选电影票*
其中,有这样的一段代码:
//创建一个元素(对象),表示已经选择的票
var selectedBtn = document.createElement("button");
...(忽略这些代码)
//绑定回调函数
selectedBtn.onclick = cancelSelected;
//记录对应的票
selectedBtn.ticket = ticket;
//渲染
selected.appendChild(selectedBtn);
解释:每当单击一个未选择的座位(选票操作),就会在“已经选择”的区域产生一个提示的“标签”,点击这个“标签”可以取消对票的选择。在上面的例子中,每选择一张票,就会生成一个“标签”,并且给这个“标签”绑定一个响应函数(取消选择)。
给祖先元素(一般使用父元素)绑定回调函数(响应函数)
上面的例子中这里的事件全都自己处理,现在要将这些事件,委托给父元素处理
//获取父元素
let selected = document.getElementById("selected");
//给父元素绑定响应函数
selected.onclick = cancelSelected;
之前没有委托给祖先元素处理时,回调函数的隐式参数this
为事件的触发者;现在,委托给祖先元素后,隐式参数this
是祖先元素本身。又有新的问题出现了怎么获取事件的触发者?
在祖先元素的响应函数中,获取事件的触发者:Event.target
事件对象中有一个target属性,Event.target
,表示事件的触发者,这样,就可以在祖先元素的响应函数中获取触发事件的后代元素
/**委托给父元素的响应函数
* @param {Object} event 事件对象
*/
function cancelSelected(event){
//获取触发事件的元素
let target = event.target;
//修改座位状态为未选中
target.seat.selected = false;
//修改总价格
var totalPrice = document.getElementById("totalPrice");
let money = Number(totalPrice.innerHTML);
totalPrice.innerHTML = money - target.ticket.price;
//删除结点
target.parentNode.removeChild(target);
//修改座位颜色
target.seat.style.backgroundColor = "rgb(239, 239, 239)"
}
避免父元素本身触发事件
现在,基本功能已经实现,但是有一个BUG。如果现在单击父元素,就会出现错误,现在的target === this
,target
不是子元素。
解决方式一:判断target === this
,如果为true
,就表示触发事件的是祖先元素,事件处理函数字节返回,不执行任何操作。
function cancelSelected(event){
//获取触发事件的元素
let target = event.target;
if(this === target)
return ;
...(后代元素触发事件后,要处理的操作)
}
解决方式二:根据html标签名判断是否为子元素。子元素是一个button
元素,对应的tagName
为BUTTON
,只需要判断触发事件的对象target
的标签名是否为BUTTON
,即可区分它和祖先元素。
关键点:代理对象(祖先)和被代理对象(后代)的标签名不能一样
function cancelSelected(event){
//获取触发事件的元素
let target = event.target;
if(target.tagName !== "BUTTON")
return ;
}
除了上述两种解决方式,还可以通过css
的class
属性来判断。通过target.className
可以获取。通过class
来判断时,要注意可能会有多个空格间隔的字符串
,因此可以使用正则表达式进行判断。