1. 如何绑定事件处理函数: 3种:
(1). 在HTML元素开始标签中绑定
Html中: <元素 on事件名="js语句">
Js中: function 事件处理函数(){
...
}
问题: 不便于维护,不符合内容与行为分离的原则
(2). 在js中用赋值方式绑定:
元素对象.on事件名=function(){
... this->当前正在触发事件的元素对象 ...
}
问题: 一个元素的一个事件属性只能绑定一个处理函数!
(3). 添加事件监听对象的方式:
a. 元素对象.addEventListener("事件名", 事件处理函数)
添加事件监听对象
b. 原理:
c. 移除事件监听对象:
1). 元素.removeEventListener("事件名",原处理函数)
移除 事件 监听对象
2). 结果: 去事件监听队列中查找完全吻合的一个监听对象删除掉!
完全吻合:元素相同,事件名相同,处理函数对象也要相同(同一个函数对象)
3). 问题: 如果仅仅把处理函数写的和绑定时完全一样,是无法移除原处理函数
4). 原因: 移除时,要求使用的函数的地址必须和绑定时使用的函数地址完全一样,也就是说必须是同一个函数对象,才可以移除
5). 解决: 今后如果一个函数可能被移除,则在绑定时,就不能使用匿名函数,必须使用有名称的函数!
1. DOM标准的事件模型: 当事件发生时,其实会经历三个阶段!
(1). 由外向内的捕获阶段: 从dom树根节点开始,到当前点击的元素位置,遍历并记录当前元素各级父元素上绑定的事件处理函数。但是只记录,暂不触发!
(2). 目标触发阶段: 优先触发当前点中的元素上的事件处理函数
目标元素(target): 实际想点击的那个触发事件的元素
(3). 冒泡执行阶段: 按捕获阶段记录的各级父元素上的处理函数顺序,由内向外反向触发各级父元素上的事件。
2. 事件对象:
(1). 什么是事件对象: 当事件发生时,浏览器自动创建的,保存事件信息的对象。同时还提供了改变事件默认特征的功能
(2). 何时使用: 今后只要希望获得事件信息,或改变事件默认的特征时,只能用事件对象
(3). 如何获得事件对象:
a. 不用自己创建,但是得自己想办法拿到才能用!
b. 获取事件对象: 事件对象总是默认作为事件处理函数的第一个实参值自动传入
所以,只要给事件处理函数定义一个形参,即可接住事件对象
//当触发事件时自动创建event对象
↓
元素.on事件名 = function( e ){
e=event对象
}
强调: 只要想使用事件对象e,都必须为事件处理函数添加第一个形参e
(4). 能干什么?
a. 停止冒泡:
1). e.stopPropagation()
停止 蔓延;向外扩散
2). 特点: 不阻止当前元素上事件处理函数的执行,而是阻止父元素上事件处理函数的执行!
3). 示例: 停止冒泡
<head> <title>事件处理</title> <meta charset="utf-8"/> <style> #d1 #d2 #d3{cursor:pointer} #d1 {
position: relative; 150px; height: 150px; text-align: center; cursor: pointer; } #d2 {
position: absolute; top: 25px; left: 25px; 100px; height: 100px; } #d3 {
position: absolute; top: 25px; left: 25px; 50px; height: 50px; line-height: 50px; } </style> </head> <body> <div id="d1"> <div id="d2"> <div id="d3"> </div> </div> </div> <script> //为外中内三个div都绑定单击事件 //希望点谁,只有谁喊自己疼! var d1=document.getElementById("d1"); var d2=document.getElementById("d2"); var d3=document.getElementById("d3"); d1.onclick=function(){ alert(`${this.id} 疼!`) } d2.onclick=function(e){ e.stopPropagation(); //不阻止d2的onclick,而是阻止d1的onclick alert(`${this.id} 疼!`) } d3.onclick=function(e){ e.stopPropagation(); alert(`${this.id} 疼!`) } </script> </body> |
b. 利用冒泡/事件委托/事件代理 event delegate
委托 代理
1). 问题: 浏览器触发事件处理函数是用遍历事件监听对象队列的方式来找到符合条件的事件监听对象,执行其中的处理函数。如果队列中被添加的事件监听对象的个数过多,遍历就会慢!事件响应的速度慢!
2). 优化: 尽量减少事件绑定或事件监听对象的个数!
3). 何时: 只要一个父元素下的多个平级子元素都需要绑定同一个事件时,都必须用事件委托优化!
4). 如何: 只要将事件只绑定在公共的父元素上一份即可!所有子元素,都可通过冒泡这个机制,冒泡到父元素上执行事件处理函数!
5). 两个难题:
i. this无法获得目标元素了:
①原因: 事件绑定在父元素上,所以this指父元素,不再指当前点击的目标元素了!因为事件处理函数在哪个元素上执行,this就指谁!
②解决: 其实事件对象e中始终保存着一个属性e.target,保存着最初触发事件的那个目标元素!e.target不会随冒泡而改变自己的初心——一旦拥有别无所求!
③结论: 今后只要使用事件委托,都用e.target代替this来获得目标元素
ii. 点父元素下其余子元素或点父元素本身也会触发事件:
①解决: 今后只要使用事件委托,都要先判断当前点击的目标元素是不是想要的!只有当前单击的目标元素e.target是想要的那种元素,才执行后续操作。否则,就什么也不干
c. 阻止元素自带的默认行为:
1). 有些HTML元素上自带一些默认行为:
i. <a href="#"></a> 当点击a时,会自动在地址栏末尾加#
ii. <form>元素中的<input type="submit">和<button>点击后,默认会自动提交表单!
2). 何时阻止默认行为: 只要元素自带的这些自动的默认行为不是我们想要的!都可以阻止!——就像什么都没有发生一样
3). 如何: e.preventDefault();
阻止 默认
4). 但是: 以上两种情况其实可以规避,换成没有默认行为的元素或写法即可
i. <a href="javascript:;">
ii. <input type="button">
5). 示例: 阻止a元素和提交按钮的默认行为:
<body> <a id="a1" href="#">click me</a> <a id="a1" href="javascript:;">click me</a> <form> <input name="uname"><input id="btn1" type="submit"> <input type="button"> </form> <script> //想阻止a的默认行为,而执行我们自己的操作 var a1=document.getElementById("a1"); a1.onclick=function(e){ e.preventDefault(); alert(`a1 疼!`); } var btn1=document.getElementById("btn1"); btn1.onclick=function(e){ e.preventDefault(); alert("btn1 疼!"); } </script> </body> |
d. 鼠标坐标:
1). 当鼠标点击或移动时,触发事件,在事件对象中都会保存鼠标当前所在位置的x、y坐标
2). 其实这个坐标有三组:
i. 当前鼠标位置相对于整个显示屏左上角坐标
e.screenX e.screenY
ii. 当前鼠标位置相对于文档显示区左上角坐标
e.clientX e.clientY
客户端
iii. 当前鼠标位置相对于当前点击的元素左上角坐标
e.offsetX e.offsetY
偏移量