事件高级
注册事件
-
传统注册方式 (利用on开头的事件):
同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数 -
方法监听注册方式(w3c标准推荐方式):
同一个元素同一个事件可以注册多个监听器按注册顺序依次执行
addEventListener()是一个方法,有兼容性问题,IE9之前可使用attachEvent()或传统注册方式代替
addEventListener()
eventTarget.addEventListener(type,listener[, useCapture])
方法将指定的监听器注册到eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数。该方法接收三个参数∶
type: 事件类型字符串,比如click、mouseover,注意这里不要带on
listener: 事件处理函数,事件发生时,会调用该监听函数 可以添加多个
useCapture: 可选参数,是一个布尔值,默认是false。
attachEvent() (MDN不推荐使用)
注册事件兼容性解决方案
function addEventListener(element,eventName,fn) {
//判断当前浏览器是否支持addEventListener方法
if(element.addEventListener) {
element.addEventListener(eventName,fn);ll第三个参数默认是false
}else if (element.attachEvent){
element.attachEvent ( 'on' + eventName,fn) ;
}else {
//相当于element.onclick = fn;
element[ 'on' + eventName] = fn;
}
}
注意:
兼容性处理的原则:首先照顾大多数浏览器,再处理特殊浏览器
删除(解绑)事件
- 传统注册方式
eventTarget.onclick = null;
- 方法监听注册方式
// 1. removeEventListener 删除事件 兼容性问题
divs[1].addEventListener('click', fn) //里面的fn 不需要调用加小括号
function fn() {
alert(22);
divs[1].removeEventListener('click', fn);
}
// 2. detachEvent 删除事件
divs[2].attachEvent('onclick', fn1);
function fn1() {
alert(33);
divs[2].detachEvent('onclick', fn1);
}
DOM事件流
事件流描述的是从页面中接收事件的顺序。
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流。
DOM事件流分为3个阶段∶
- 捕获阶段
- 当前目标阶段
- 冒泡阶段
注意:
- Js 代码中只能执行捕获或者冒泡其中的一个阶段。
- onclick和attachEvent只能得到冒泡阶段。
- addEventListener(type,listener[,useCapture])第三个参数如果是true,表示在事件捕获阶段调用事件处理程序; 如果是false (不写默认就是false),表示在事件冒泡阶段调用事件处理程序。
- 实际开发中我们很少使用事件捕获,更关注事件冒泡
- 有些事件是没有冒泡的,比如onblur、onfocus、onmouseenter、onmouseleave
事件对象
eventTarget.onclick = function (event) { }
eventTarget.addEventListener('click', function(event) {})
- event 就是一个事件对象 写到我们侦听函数的 小括号里面 当形参来看
- 事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
- 事件对象 是 我们事件的一系列相关数据的集合 跟事件相关的 比如鼠标点击里面就包含了鼠标的相关信息,鼠标坐标啊,如果是键盘事件里面就包含的键盘事件的信息 比如 判断用户按下了那个键
- 这个事件对象我们可以自己命名 比如 event 、 evt、 e
- 事件对象也有兼容性问题 ie678 通过 window.event 兼容性的写法 e = e || window.event;
常见事件对象的属性和办法
e.target 与this区别:
- e.target 返回的是触发事件的对象(元素),e.target 点击了哪个元素,就返回哪个元素
- this 返回的是绑定事件的对象(元素),this 哪个元素绑定了这个点击事件,那么就返回谁
<script>
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// 我们给ul 绑定了事件 那么this 就指向ul
console.log(this);
console.log(e.currentTarget);
// e.target 指向我们点击的那个对象 谁触发了这个事件 我们点击的是li e.target 指向的就是li
console.log(e.target);
})
// 2. 了解 跟 this 有个非常相似的属性 currentTarget 但有兼容性问题
</script>
阻止默认行为 - e.preventDefault()
//让链接不跳转 或者让提交按钮不提交
var a = document.querySelector('a');
a.addEventListener('click', function(e) {
e.preventDefault(); // dom 标准写法
})
// 传统的注册方式
a.onclick = function(e) {
// 普通浏览器 e.preventDefault(); 方法
// e.preventDefault();
// 低版本浏览器 ie678 returnValue 属性
// e.returnValue;
return false;
alert(11);
}
注意:
我们可以利用return false 也能阻止默认行为 没有兼容性问题
特点: return 后面的代码不执行了, 而且只限于传统的注册方式
阻止事件冒泡(重点) e.stopPropagation()
<script>
// 常见事件对象的属性和方法
// 阻止冒泡 dom 推荐的标准 stopPropagation()
var son = document.querySelector('.son');
son.addEventListener('click', function(e) {
alert('son');
e.stopPropagation(); // stop 停止 Propagation 传播
e.cancelBubble = true; // 非标准 cancel 取消 bubble 泡泡
}, false);
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, false); //son阻止冒泡了 但是father没有定义 因此点击father还是会向上冒泡
document.addEventListener('click', function() {
alert('document');
})
</script>
事件委托(代理、委派)
事件委托也称为事件代理,在jQuery里面称为事件委派。
事件委托的作用
我们只操作了一次DOM,提高了程序的性能。
事件委托的原理
不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
比如给ul注册点击事件,然后利用事件对象的target来找到当前点击的li,因为点击li,事件会冒泡到ul上,ul有注册事件,就会触发事件监听器。
// 事件委托的核心原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// e.target 这个可以得到我们点击的对象
e.target.style.backgroundColor = 'pink';})
常用鼠标事件
- 禁止鼠标右键菜单
contextmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单
document.addEventListener ( 'contextmenu', function(e) {
e.preventDefault();
})
- 禁止鼠标选中( selectstart开始选中)
document.addEventListener ( 'selectstart', function (e) {
e.preventDefault () ;
})
- 鼠标事件对象
event对象代表事件的状态,跟事件相关的一系列信息的集合。现阶段我们主要是用MouseEvent和键盘事件对象KeyboardEvent。
常见键盘事件
注意∶
- 如果使用addEventListener不需要加on
- onkeypress和前面2个的区别是,它不识别功能键,比如左右箭头,shift等。
- 三个事件的执行顺序是: keydown— keypress — keyup
键盘事件对象
e.keyCode属性可以得到相应键的ASCII码值
键盘按键与 ASCII 字符集对照表:https://www.runoob.com/note/29592
注意:
-
onkeydown和onkeyup 不区分字母大小写,onkeypress区分字母大小写。
-
在我们实际开发中,我们更多的使用keydown和keyup,它能识别所有的键(包括功能键)
-
Keypress不识别功能键,但是keyCode属性能区分大小写,返回不同的ASCIl值
案例-模拟京东快递单号输入
<body>
<div class="search">
<div class="con">123</div>
<input type="text" placeholder="请输入您的快递单号" class="jd">
</div>
<script>
// 快递单号输入内容时, 上面的大号字体盒子(con)显示(这里面的字号更大)
// 表单检测用户输入: 给表单添加键盘事件
// 同时把快递单号里面的值(value)获取过来赋值给 con盒子(innerText)做为内容
// 如果快递单号里面内容为空,则隐藏大号字体盒子(con)盒子
var con = document.querySelector('.con');
var jd_input = document.querySelector('.jd');
jd_input.addEventListener('keyup', function() {
// console.log('输入内容啦');
if (this.value == '') {
con.style.display = 'none';
} else {
con.style.display = 'block';
con.innerText = this.value;
}
})
// 当我们失去焦点,就隐藏这个con盒子
jd_input.addEventListener('blur', function() {
con.style.display = 'none';
})
// 当我们获得焦点,就显示这个con盒子
jd_input.addEventListener('focus', function() {
if (this.value !== '') {
con.style.display = 'block';
}
})
</script>
</body>