DOM事件模型
dom事件模型分为脚本模型,内联模型和动态绑定三种。
<html>
<body>
<!--行内绑定:脚本模型-->
<div onclick="javascrpt:alert('eventType1')" id="eventType1">脚本模型</div>
<!--内联模型: 多次声明,只能绑定一次,后声明,后生效-->
<div onclick="sayType" id="eventType2">内联模型</div>
<!--动态绑定:可以绑定多次,都可生效-->
<div id="eventType3">动态绑定</div>
</body>
<script>
function sayType(){
alert('eventType2-1')
}
// 会覆盖之前的事件声明
document.getElementById('eventType2').onclick = function(){
alert('eventType2-2')
}
var eventType3Dom = document.getElementById('eventType3')
eventType3Dom.onclick = function(){
alert('eventType3-1')
}
// 生效
eventType3Dom.addEventListener('click',function(){
alert('eventType3-2')
})
// 生效
eventType3Dom.addEventListener('click',function(){
alert('eventType3-2')
})
</script>
</html>
DOM事件流
DOM结构是一个树型结构,当一个HTML元素产生一个事件时,该事件会在元素结点与根结点之间的路径传播,路径所经过的结点都会收到该事件,这个传播过程可称为DOM事件流。DOM同时支持两种事件模型:捕获型事件和冒泡型事件。
"DOM2事件流"规定的事件流包括三个阶段:事件捕获阶段,处于目标阶段,事件冒泡阶段。
事件捕获阶段
document对象首先接收到事件,然后事件沿着DOM树依次向下,一直传播到事件的实际目标。
事件捕获的用意在于在事件到达预定目标之前就捕获它。给addEventListener第三个参数传入true即可监听捕获事件。
<html>
<body>
<div id="div">div</div>
</body>
<script>
document.getElementById('div').addEventListener('click',function(){
alert('div')
},true)
document.addEventListener('click',function(){
alert('html')
},true)
document.body.addEventListener('click',function(){
alert('body')
},true)
</script>
</html>
依次打印html body div
事件捕获阶段
事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点。
<html>
<body>
<div id="div">div</div>
</body>
<script>
document.getElementById('div').addEventListener('click',function(){
alert('div')
},true)
document.addEventListener('click',function(){
alert('html')
},true)
document.body.addEventListener('click',function(){
alert('body')
},true)
</script>
</html>
依次打印div body html
阻止冒泡
function stopBubble(e) {
//如果提供了事件对象,则这是一个非IE浏览器
if ( e && e.stopPropagation ) {
//因此它支持W3C的stopPropagation()方法
e.stopPropagation();
} else {
//否则,我们需要使用IE的方式来取消事件冒泡
window.event.cancelBubble = true;
}
}
阻止默认行为
function stopDefault( e ) {
//阻止默认浏览器动作(W3C)
if ( e && e.preventDefault ) {
e.preventDefault();
//IE中阻止函数器默认动作的方式
} else {
window.event.returnValue = false;
}
return false;
}
DOM事件的一些优化方法
事件委托
事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
<ul id="parent">
<li class="child">one</li>
<li class="child">two</li>
<li class="child">three</li>
</ul>
<script>
//父元素
var dom= document.getElementById('parent');
//父元素绑定事件,代理子元素的点击事件
dom.onclick= function(event) {
var event= event || window.event;
var curTarget= event.target || event.srcElement;
if (curTarget.tagName.toLowerCase() == 'li') {
//事件处理
}
}
</script>
局限性:
- focus、blur 之类的事件本身没有事件冒泡机制,所以无法委托
- mousemove、mouseout 这样的事件,虽然有事件冒泡,但是只能不断通过位置去计算定位,对性能消耗高,不适合事件委托
节流函数解决频繁回调的事件
规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
function throttle(fn,delay){
var flag = true;
var _this = this;
return function(){
if (flag === false) {
return;
}
flag = false;
var args = arguments;
setTimeout(function(){
fn.apply(_this, args);
flag = true;
},delay || 500);
}
}
// onsize事件
window.onresize = throttle(function (e)
console.log(123);
}, 500)
防抖函数解决连续触发事件
在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
<button id="button">连续点击</button>
<script>
function debounce (fn, delay){
var timer = null;
var _this = this;
return function(){
var args = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
fn.apply(_this, args);
},delay || 500);
}
}
// 500ms只执行一次
document.getElementById('button').addEventListener('click',debounce(function(){
console.log(123)
}))
</script>