DOM触发事件方法
1.html attribute 标签中添加事件属性
<input value="Click me" onclick="alert('Click!')" type="button">
js逻辑在属性里创建,不是很好,写到一个方法里.
<script>
function countRabbits() {
for(let i=1; i<=3; i++) {
alert("Rabbit number " + i);
}
}
</script>
<input type="button" onclick="countRabbits()" value="Count rabbits!">
因为html属性不区分大小写,所以你onClick可以随你写,ONCLICK, onCLICK, 最好是onclick.
2.dom property 元素属性赋值
<input id="elem" type="button" value="Click me">
<script>
elem.onclick = function() {
alert('Thank you');
};
</script>
这个方式直接在dom上绑定,上面的html-attribute是浏览器读取他创建函数对象写入dom中。
处理程序始终位于dom property中:html attribute 只是初始化它的一个方法,并且也不被推荐。
如果html attributre 存在事件绑定,并且dom也存在事件绑定,相同的事件将被dom中的给替代。
直接给元素加事件属性(DOM0级模型)是注册事件最简单的方法,将处理程序赋值给相应的事件属性(事件前面带on)。这种方式适用于所有浏览器。但是缺点是元素将最多只有一个事件处理程序。
dom绑定的一些写法.
<input id="elem" type="button" value="Click me">
<script>
//1
elem.onclick = function() {
alert('Thank you');
};
//2
function thank() {
alert('thank you')
}
elem.onclick = thank;
</script>
// 但是如果是input中也是不同的。
<input id="elem" type="button" value="Click me" onclick="thank()">
3.addEventListener
事件处理程序的注册方法为addEventListener()
,它接受3个参数(事件类型,事件回调函数,布尔值),其中最后一个参数默认值为false,将会把程序注册为冒泡事件处理程序。而其若为true,则为捕获事件处理程序。两者的区别是:若为冒泡,表示在冒泡阶段调用事件处理程序,逐渐冒泡到外层。而捕获恰好相反,在捕获阶段调用处理程序,执行顺序相反。在IE中只支持事件冒泡。移除事件使用removeEventListener()
,传参如上。
IE8及以下浏览器不支持此方法,使用attachEvent(on+事件类型, 事件回调函数)
方法,只有两个参数(不支持事件捕获)。移除事件使用detachEvent()
方法,参数相同。
<button id="elem">Click me</button>
<script>
elem.addEventListener('click', {
handleEvent(event) {
alert(event.type + " at " + event.currentTarget);
}
});
</script>
上面的方法使用到了handleEvent
, 如果发生事件,handleEvent会被调用。
也可以那么说,当addEventListener接收到处理程序对象时,事件会去调用object.handleEvent(event)
。
等同于:
<button id="elem">Click me</button>
<script>
elem.addEventListener('click',function(event) {
alert(event.type + " at " + event.currentTarget);
});
</script>
如下,很实用的方法。
<button id="elem">Click me</button>
<script>
class Menu {
handleEvent(event) {
// mousedown -> onMousedown
let method = 'on' + event.type[0].toUpperCase() + event.type.slice(1);
this[method](event);
}
onMousedown() {
console.log(1)
}
onMouseup() {
console.log(2)
}
}
let menu = new Menu();
elem.addEventListener('mousedown', menu);
elem.addEventListener('mouseup', menu);
</script>
注意:dom添加赋值事件属性方式(普通事件)可以被第二次调用的同一个事件覆盖,而addEventListener
事件绑定不会被覆盖,而是会依次执行。
事件流
事件流:事件流是描述从页面中接收事件的顺序。也可以说是事件传播的顺序。
“DOM2事件流”规定的事件流包括三个阶段:
- 事件捕获阶段:提供了在事件没有送达目标之前查看事件的机会。与冒泡方向相反,由父向子逐级捕获。
- 处于目标阶段:目标对象(元素)本身的时间处理程序调用(执行)。
- 事件冒泡阶段。目标元素的事件大部分都会冒泡(传播)到DOM树根。有一些特殊的事件不会冒泡,比如mouseenter和mouseleave事件不会冒泡。若要冒泡,可以使用mouseover和mouseout替代。
事件模型
js包含三种事件模型:DOM0事件模型(始事件模型),DOM2事件模型,IE事件模型
- DOM0级模型:事件不会流动传播。事件绑定监听函数方式:① html标签中添加属性如
<div onclick="fun()"></div>
;② js中获取dom元素后给元素加事件属性:document.onclick = fn
,取消监听使用document.onclick = null
- IE事件模型:使用
attachEvent("onclick", handler)
和detachEvent("onclick", handler)
方法进行绑定事件和移除绑定。事件流只有2个阶段,没有事件捕获阶段。 - DOM2级模型:
addEventListener()
和removeEventListener()
进行监听和取消。事件流有3个阶段。
事件冒泡
就是一个事件(例如点击),这个点击会往上层元素进行冒泡(往上进行),他是从点击的这个元素(目标元素,即event.target
)开始向上去冒泡。
这里开始,先搞清两个点event.target
和event.currentTarget
event.target
是当前点击的元素(目标元素)
event.currentTarget
也就是this
, 是绑定函数操作的元素(addEventListener
绑定的元素,有可能是目标元素的父元素)
有的时候你可能并不想他去冒泡,可以通过stopPropagation
这个方法去干掉他。
- event.stopPropagation()
这个方法有个地方需要注意一下,那就是当一个事件有多个处理程序的时候,他只会停止当前程序的冒泡,其他的程序不会收到影响,需要解决这个问题,就需要使用到event.stopImmediatePropagation
方法。
尽量不要阻止事件冒泡,除非你知道
你自己在干什么。
当你调用return false
时会做 3 件事:
- event.preventDefault() – 它停止浏览器的默认行为。
- event.stopPropagation() – 它阻止事件传播(或“冒泡”)。
- 停止回调执行并立即返回。
事件捕获
事件捕获和事件冒泡是不同的,捕获是从上而下。如果需要捕获事件,那就需要将addEventListener
的第三个参数(叫做useCapture
)设置成true
.
默认的false
是在冒泡阶段处理事件,true
就是捕获阶段处理事件。看下面的代码:
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<form>FORM
<div>DIV
<p>P</p>
</div>
</form>
<script>
for(let elem of document.querySelectorAll('*')) {
elem.addEventListener("click", e => alert(`Capturing: ${elem.tagName}`), true);
elem.addEventListener("click", e => alert(`Bubbling: ${elem.tagName}`));
}
</script>
运行之后,发现两个顺序是相反的。而且点击的元素是位于捕获阶段的最后,冒泡阶段的开始。
本文固定连接:https://code.zuifengyun.com/2020/03/2105.html,转载须征得作者授权。