DOM 事件
-
事件是什么?
在Web应用程序中,事件就是将应用程序内的发生的动作或者发生的事情告知浏览器,浏览器给出响应。
-
事件和JavaScript有什么关系?
事件是客户端(浏览器)的一种处理机制,事件机制与JavaScript并不存在存在直接联系,联系的建立是依靠客户端来实现的,事件机制本身并不是JavaScript语言的内容。
简单来说,DOM事件并不是JavaScript的功能,而是浏览器支持的功能,我们只是使用JavaScript来完成事件的监听和对事件做出响应。
事件绑定
HTML内联绑定事件
HTML中直接绑定DOM,就是在HTML的元素中使用<event>
属性来绑定事件,比如onclick
这样的on(type)
属性,其中type指的就是DOM的事件(比如click),它可以给这个DOM元素绑定一个类型的事件。
<button onclick="show();">Click Me</button>
<script>
function show() {
console.log('Show Me!')
}
</script>
JavaScript中绑定DOM事件
在JavaScript中绑定DOM事件有两种方法:
-
element.on(type) = listener
let btn = document.querySelector('button') btn.onclick = function () { console.log("Show Me!"); //被覆盖 }; btn.onclick = function () { console.log("Show Me again!"); //最终绑定 };
按照DOM事件级别分类,上面的方法是DOM0级事件,就是将一个函数赋值给一个事件处理属性,优点是降低HTML和JS的耦合,并且处理函数可以接收浏览器创建的事件对象event作为参数,缺点在于无法同时给同一个DOM元素绑定多个处理函数,执行上面两次绑定时,下面的函数就会覆盖上面的。
-
element.addEventListener(type, listener, useCapture)
参数:
element:表示要监听事件的目标对象
type:表示事件类型的字符串,比如click、change、touchstart等
listener:当指定的事件类型发生时被对知到的一个对象,一般是是一个函数。
useCapture:设置事件的捕获或者冒泡,它有两个值,其中true表示事件捕获,为false是事件冒泡,默认值为false
<button>Click Me!</button> <script> function show (e) { console.log("Show Me!") console.log(e) } let btn = document.querySelector('button') btn.addEventListener('click', show, false) </script>
按照DOM事件级别分类,上面的方法是DOM2级事件,优点是可以给同一个DOM元素绑定多个处理函数,并且遵循“先绑定先触发”的原则,处理函数可以接收浏览器创建的事件对象event作为参数。
事件对象
当事件发生时,浏览器会创建一个事件对象,将详细信息放入这个对象当中,下图是把代码中点击事件对象event打印出来的结果。
Event
对象在event
第一次触发的时候被创建出来,并且一直伴随着事件在DOM结构中流转的整个生命周期(当事件结束后,可以认定为对象也消失了,所有当想一直使用event对象的数据时,可以赋值给其他对象来保留数据)。event
对象会被作为第一个参数传递给事件监听的回调函数。我们可以通过这个event
对象来获取到大量当前事件相关的信息,下面挑选几个重要的参数:
-
type (String)
:事件的名称 -
target (node)
:事件起源的DOM节点,可以理解为用户操作的元素 -
currentTarget?(node)
:当前回调函数被触发的DOM节点,可以理解为用户监听的元素?详细信息MDN文档
DOM事件流
<div onclick="parent">
<div onclick="child">click</div>
</div>
上面的代码中,在子元素和父元素上都注册了点击事件,当点击文字时,是先触发父元素上的事件函数,还是子元素上的事件函数呢,这就需要一种约定去规范事件的执行顺序,就是事件执行的流程。 浏览器在发展的过程中出现了两种不同的规范:
- IE9以下的IE浏览器使用的是事件冒泡,由内向外找监听函数。
- Netscapte采用的是事件捕获,由外向内找监听函数。
- 而W3C制定的Web标准中,是同时采用了两种方案,事件捕获和事件冒泡都可以。
W3C事件模型
W3C规范中定义了三个事件传播阶段,依次是捕获阶段、目标阶段和冒泡阶段。
-
捕获阶段(Capture Phase):事件从window对象自上而下向目标节点传播的阶段;
-
目标阶段(Target Phase):真正的目标节点正在处理事件的阶段;如果一个事件对象类型被标志为不能冒泡,那么对应的事件对象在到达此阶段时就会终止传播。
-
冒泡阶段(Bubbling Phase):事件从目标节点自下而上向window对象传播的阶段。
给DOM元素绑定事件都会经历三个传播阶段,当事件发生时,始终从根开始,沿着路径直到达到目标,然后再重新追溯根源,然后回到根。而其中启动事件的部分和事件从根向下寻找目标称为事件捕获阶段,从目标回到根的阶段为冒泡阶段。
-
IE的API:
element.attachEvent('oncIick', (n)
//指定为冒泡阶段被触发 -
Netscapte的API:
element.addEventListener('cIick',fn)
/ /指定为捕获阶段被触发 -
W3C的API:
element.addEventListener('cIick',fn,bool)
bool没有值或值为falsy——冒泡
bool值为ture——捕获
事件中断
现实中,很多时候我们并不希望目标元素的事件结束之后还去追溯其根源(冒泡)。在JavaScript中可以在事件对象上使用stopPropagation方法来阻止目标元素的冒泡事件,但是会不阻止默认行为。
function show (e) {
e.stopPropagation();
}
取消默认事件
- 浏览器默认事件
许多事件会自动触发浏览器执行某些行为。
例如:点击一个链接 会触发导航(navigation)到该 URL,点击表单的提交按钮 会触发提交到服务器的行为。
- 取消方法
- 使用
event
对象的event.preventDefault()
方法
<a href="/" onclick="event.preventDefault()">here</a>
- return false
<a href="/" onclick="return false">Click here</a>
事件委托
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的委托(delegation)。
适用场景
场景一:给N个同级元素添加点击事件
解决:使用事件委托,在父元素parent上设置监听函数
<div id="parent">
<button data-id="1">1</button>
<button>2</button>
<button>3</button>
<button>4</button>
<button>5</button>
</div>
<script>
parent.addEventListener('click',(e)=>{
const t=e.target
if(t.target.toLowerCase()=='button'){
console.log("button被点击了");
console.log('button的data-id是'+t.dataset.id);
}
})
</script>
场景二:监听目前还不存在的元素的点击事件
解决:先监听父元素, 等点击的时候看看是不是我想要监听的元素即可
<div id="parent"> </div>
<script>
setTimeout(()=>{
const button=document.createElement('button')
button.textContent='button'
parent.appendChild(button)
},1000)
parent.addEventListener('click',(e)=>{
const t=e.target
if(t.target.toLowerCase()=='button'){
console.log("button被点击了");
}
})
</script>
优点
-
减少内存消耗,提高性能
参考场景一,不用单独给每个按钮绑定监听函数,我们只需要给父容器绑定函数即可,这样不管点击的是哪一个后代元素,都会根据冒泡传播的传递机制,把容器的click行为触发,然后把对应的方法执行,根据事件源(target),我们可以知道点击的是哪个子元素,从而完成不同的事。
-
动态绑定事件
参考场景二,那么在元素动态发生变化时,就需要给新增的元素绑定事件,给即将删去的元素解绑事件,如果用事件代理就会省去很 多这样麻烦。
参考
事件绑定的姿势
深入理解DOM事件机制
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!