事件流分为三个阶段,依次为捕获阶段(父->子)、目标阶段、冒泡阶段(子->父),事件触发顺序为捕获阶段–目标阶段–冒泡阶段;
平时给元素绑定事件一般是直接写到属性上(即0级事件处理程序)或是addEventListener()监听事件(2级事件处理程序)。但有些应用场景以上方法可能不太管用,比如给后来动态添加的元素绑定事件监听。这时就可以使用事件委托了(也叫事件代理)。事件委托简单通俗理解就是,给外层元素绑定事件,然后利用事件冒泡,针对当前触发的元素执行相应的函数。
<ul class="list">
<li>第一条</li>
<li>第二条</li>
<li>第三条</li>
</ul>
<button class="btn">添加列表</button>
<script>
var list = document.querySelector('.list');
var btn = document.querySelector('.btn');
btn.onclick = function(){
var li = document.createElement('li');
li.innerHTML = '<p>大家好<a href="javascript:;">才是真的好</a></p>'
list.appendChild(li);
}
on(list, 'click', 'a', function(){
alert(this.innerText);
})
function on(el, eventType, selector, fn){
if(fn === undefined){ //如果只传三个参数,即为自身绑定事件
fn = selector;
selector = null;
el.addEventListener(eventType, fn, false);
}else{ //如果传入四个参数,即为事件委托,selector为事件目标
el.addEventListener(eventType, function(e){
if(e.target.matches(selector)){ //如果当前时间目标与selector匹配
fn.call(e.target, e);
}
}, false);
}
}
// 方法二
function delegate(element, eventType, selector, fn) {
element.addEventListener(eventType, e => {
let el = e.target
while (!el.matches(selector)) {
if (element === el) {
el = null
break
}
el = el.parentNode
}
el && fn.call(el, e, el)
})
return element
}
</script>
示例:通过点击每张图片,弹出相应的视频
<div class="flex-contain-Main-top-flex" id="playModel_1">
<div class="flex-img1">
<img src="./assets/img/srcoll1.jpg" alt="">
</div>
<div class="flex-img2">
<img src="./assets/img/srcoll2.jpg" alt="">
</div>
<div class="flex-img3">
<img src="./assets/img/srcoll3.jpg" alt="">
</div>
<div class="flex-img4">
<img src="./assets/img/srcoll4.jpg" alt="">
</div>
</div>
<!-- dialog 弹窗模块 -->
<div id="dialog">
<div class="shadow"></div>
<div class="site-content cf">
<div class="boxed-group">
<h3>视频播放</h3>
<div class="boxed-group-inner">
<video id="myvideo" style="width:100%; height:100%; object-fit: fill" controls>
</video>
</div>
<div class="footer">
<button href="#" class="btn btn-danger boxed-action" id="cancel"
onclick="cancel()">X</button>
</div>
</div>
</div>
</div>
let videoList = [
'http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4',
'http://vjs.zencdn.net/v/oceans.mp4',
'https://media.w3.org/2010/05/sintel/trailer.mp4',
'http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4'
];
let dialog = document.getElementById("dialog");
let player = document.getElementById('playModel_1');
let video = document.getElementById('myvideo');
dialog.style.display = "none";
on(player, 'click','img',function (e) {
let parent = e.target.parentElement;
let index =Array.prototype.indexOf.call(parent.parentNode.children, parent);
dialog.style.display = '';
video.src = videoList[index]
});
function on(el, eventType, select, fn) {
if (fn === undefined){ // 自身绑定
fn = select;
select = null;
el.addEventListener(eventType, fn , false)
}else {
el.addEventListener(eventType,function (e) {
if (e.target.matches(select)){
fn.call(e.target,e)
}
},false)
}
}
function cancel() {
let videoPlayer = document.getElementById('myvideo');
videoPlayer.pause();
dialog.style.display = "none";
}