首先展现我们的操作页面的搭建,我们从其触发顺序来得知事件捕获和事件冒泡的原理。
<div>
<div id="a">
<div id="b">
<div id="c"></div>
</div>
</div>
</div>
然后分别对#a,#b,#c绑定click事件
<script>
document.getElementById('a').addEventListener('click',function () {
console.log(1)
},true);
document.getElementById('b').addEventListener('click',function () {
console.log(2)
},true);
document.getElementById('c').addEventListener('click',function () {
console.log(3)
},true);
document.getElementById('a').addEventListener('click',function () {
console.log(6)
},false);
document.getElementById('b').addEventListener('click',function () {
console.log(5)
},false);
document.getElementById('c').addEventListener('click',function () {
console.log(4)
},false);
</script>
点击c
输出:1->2->3->4->5->6
true的时候,属于事件捕获:从外到里触发;
事件捕获都是从window->document->html->body->div#a->div#b->div#c
false的时候,属于事件冒泡:从里到外触发
preventDefault():阻止特定事件的默认行为。比如超链接的默认行为是被单机时会导航到href的url中,若想要取消这个默认行为的发生,那就在超链接的onclick事件处理程序中取消它(event.preventDefault())。
stopPropagation():立即停止事件在DOM层次中的传播。如取消进一步的事件捕获或冒泡(even.stopPropagation())。
事件对象:
document.getElementById("a").addEventListener('click',function (e) {
console.log(e);
})
浏览器在触发click事件时包装一个对象,里面是事件的信息。从回调中返回。
事件委托:
<body>
<ul id="ul">
<li>吃饭</li>
<li>睡觉</li>
<li>打球</li>
<li>洗澡</li>
</ul>
<input type="'text" id="input">
<button id="btn">add</button>
<script>
var list = document.querySelectorAll('#ul li');
console.log(list);
for(var i = 0,len = list.length;i < len;i++){
list[i].addEventListener('click',function () {
alert(this.innerHTML)
},false)
}
document.querySelector('#btn').addEventListener('click',function () {
var text = document.querySelector('#input').value;
var li = document.createElement('li')
li.innerHTML = text;
li.addEventListener('click',function () {
alert(this.innerHTML)
})
document.querySelector('#ul').appendChild(li);
},false)
</script>
</body>
在我添加的这个li中,还需要给他绑定事件,如果有成百上千的要添加,就太繁琐了吧。
由此就有事件委托。
jQuery实现事件代理:
$('#ul').click('#ul li',function () {
alert(1);
})
$('#btn').click(function () {
$('#ul').append('<li>adasda</li>')
})
这样动态添加的li是直接绑定着事件的。
我们来看看其实现:
document.querySelector('#ul').addEventListener('click',function (e) {
console.log(e.target);
})
//<li>洗澡</li>
arget就是实际捕获的元素。
事件有三个阶段:捕获,目标,冒泡。
实现一个on,来实现事件代理
function on(ele, type, selector,fn) {
if(fn === undefined){
fn = selector;//表示selector没有传,比如on(ele,'click',function(){}),就把selector部分直接赋值给fn代替
selector = null;
}
ele.addEventListener(type,function (e) {
if(selector){//如果true,就需要事件代理
if(e.target.matches(selector)) fn.call(e.target,e);//e.target和selector去匹配,匹配到的话,就去执行fn。把e.target作为this传给fn,然后把事件对象e传递过去。这就完成了事件代理
return;
}
fn.call(e.currentTarget,e);
// fn(e);
})
}
on(document.querySelector('#ul'),'click','li',function (e) {
console.log(this);
})
// // 假如不传li,this的指向就是window,所以对上面进行修改
// on(document.querySelector('#ul'),'click',function (e) {
// console.log(this);
// })
事件处理程序:
差不多就是事件的监听器的意思,监听click、load等等事件,一般都是以“on”开头,比如onclick、onload等。
有一个很好的地方,就是它会创建一个封装着元素属性值的函数,这个函数里面有个变量——event(事件对象),在函数内部可以用this来代替事件的目标元素。
DOM0级事件处理程序:
var button = document.getElementById('btn');
button.onclick = function(){
console.log("123");
}
DOM2级事件处理程序:
var button = document.getElementById('btn');
button.addEventListener('click',function(){
console.log("123");
})