查阅更多事件方式:
https://developer.mozilla.org/zh-CN/docs/Web/Events
或者查看元素的属性(属性中onxxx就是元素拥有的事件行为)
一、常用的事件行为
事件是元素天生自带的默认操作行为
不论我们是否给其绑定了方法,当我们操作的时候,也会把对应的事件触发
事件绑定是给元素的某个行为绑定一个方法
目的是当事件行为触发的时候,可以做一些事情
1. 鼠标事件
click 点击(移动端 click 被识别为单击)
- dblclick 双击
- mousedown 鼠标按下
- mouseup 鼠标抬起
- mousemove 鼠标移动
- mouseover 鼠标滑过
- mouseout 鼠标滑出
- mouseenter 鼠标进入
- mouseleave 鼠标离开
- mousewhell 鼠标滚轮滚动
2. 键盘事件
key…
- keydown 按下某个键
- keyup 抬起某个键
- keypress 除 shift / Fn / CapsLock 键以外,其他键按住(连续触发)
3. 移动端手指事件
单手指事件模型 Touch
- touchstart 手指按下
- touchmove 手指移动
- touchend 手指松开
- touchcancel 操作取消(一般应用于非正常状态下操作结束)
多手指事件模型 Gestrue
- gestruestart
- gesturechange / gestrueundate
- gestureend
- gesturecancel
4. 表单元素常用事件
- focus 获取焦点
- blur 失去焦点
- change 内容改变
5. 音视频常用事件
- canplay 可以播放(资源没有加载完,播放中可能会卡顿)
- canplaythrough 可以播放(资源已经加载完,播放中不会卡顿)
- play 开始播放
- playing 播放中
- pause 暂停播放
6. 其他常用事件
- load 资源加载完
- unload 资源卸载
- beforeunload 当前页面关闭之前
- error 资源加载失败
- scroll 滚动事件
- readystatechange AJAX请求状态改变事件
- contextmenu 鼠标右键触发
二、DOM 0级事件
dom 0级事件绑定: dom 0级事件绑定的原理:给元素的私有属性赋值,当事件触发,浏览器会帮我们把赋的值执行,但是这样也导致 “只能给当前元素某一个事件行为绑定一个方法”
元素.on事件行为=function(){}
box.onclick = function () {
console.log('哈哈哈~~');
}
box.onclick = function () {
console.log('呵呵呵~~');
}
box.onclick = function () {
console.log('哈哈哈~~');
// 移除事件绑定:DOM0 直接赋值为 null 即可
box.onclick = null;
}
三、DOM 2级事件
dom 2级事件绑定: dom 2级事件绑定的原理:基于原型链查找机制,找到 EventTarget.prototype 上的方法并且执行,此方法执行,会把给当前元素某个事件行为绑定的所有方法,存放到浏览器默认的事件池中(绑定几个方法,会向事件池存储几个),当事件行为触发,会把事件池中存储的对应方法,依次按照顺序执行 “给当前元素某一个事件行为绑定多个不同方法”
元素.addEventListener(事件行为,function(){},true/false)
IE6~8中:元素.attachEvent('on事件行为',function(){})
box.addEventListener('click', function () {
console.log('哈哈哈~~');
}, false);
box.addEventListener('click', function () {
console.log('呵呵呵~~');
}, false);
function fn() {
console.log('哈哈哈~~');
// 移除事件绑定:从事件池中移除,所以需要指定好事件类型、方法等信息(要和绑定的时候一样才可以移除)
box.removeEventListener('click', fn, false);
}
box.addEventListener('click', fn, false);
- dom 2级事件绑定的时候我们一般都采用实名函数
- 目的:这样可以基于实名函数去移除事件绑定
- 基于 addEventListener 向事件池增加方法,存在去重机制:“同一个元素,同一个事件类型,在事件池只能存储一遍这个方法,不能重复存储”
- dom 0级事件和 dom 2级事件可以混在一起用:执行的顺序以绑定的顺序为主
box.addEventListener('click', function () {
console.log('哔咔哔咔~~');
});
box.onclick = function () {
console.log('哇咔咔~~');
}
box.addEventListener('click', function () {
console.log('call~~');
});
- dom 0级事件中能做的事件行为,dom 2级事件都支持,dom 0级事件不一定能处理绑定,例如:transitionend、DOMContentLoaded…
window.addEventListener('load', function () {
// 所有资源都加载完成触发
console.log('LOAD');
});
window.addEventListener('DOMContentLoaded', function () {
// 只要DOM结构加载完就会触发
console.log('DOMContentLoaded');
});
// $(document).ready(function(){})
$(function () {
// JQ 中的这个处理(DOM 结构加载完触发)采用的就是 DOMContentLoaded 事件,并且依托 DOM2 事件绑定来处理,所以同一个页面中,此操作可以被使用多次
});
$(function () {
}); */
// JQ 中的事件绑定采用的都是 DOM2 事件绑定,例如:on / off / one
练习题:window.onload VS $(document).ready()
- 1.$(document).ready() 采用的是 DOM2 事件绑定,监听的是 DOMContentLoaded 这个事件,所以只要DOM 结构加载完成就会被触发执行,而且同一个页面中可以使用多次(绑定不同的方法,因为基于 DOM2 事件池绑定机制完成的)
- window.onload 必须等待所有资源都加载完成才会被触发执行,采用 DOM0 事件绑定,同一个页面只能绑定一次(一个方法),想绑定多个也需要改为 window.addEventListener(‘load’, function () {})DOM2 绑定方式
三、给元素的事件行为绑定方法
给元素的事件行为绑定方法,当事件行为触发方法会被执行,不仅被执行,而且还会把当前操作的相关信息传递给这个函数 =》事件对象
如果是鼠标操作:获取的是 MouseEvent 类的实例 =》 鼠标事件对象
鼠标事件对象 -> MOuseEvent.prototoye -> UIEvent.prototype ->Event.prototype -> Object.prototype
- 如果是键盘操作:获取的是KeyboardEvent类的实例 =》 键盘事件对象
- 除了以上还有:普通事件对象(Event)、手指事件对象(TouchEvent)等
事件对象
box.onclick = function (ev) {
// 鼠标事件对象
// clientX / clientY:当前鼠标触发点距离当前窗口左上角的X / Y轴坐标
// pageX / pageY:触发点距离当前页面左上角的X / Y轴坐标
// type:触发事件的类型
// target:事件源(操作的是哪个元素,哪个元素就是事件源),在不兼容的浏览器中可以使用srcElement 获取,也代表的是事件源
// preventDefault():用来阻止默认行为的方法,不兼容的浏览器中用 ev.returnValue = false 也可以
阻止默认行为
// stopPropagation():阻止冒泡传播,不兼容的浏览器中用 ev.cancelBubble = true 也可以阻止默认行为
console.log(ev);
}
四、当事件触发时浏览器会做什么
事件对象和函数以及给谁绑定的事件没啥必然关系,它存储的是当前本次操作的相关信息,操作一次只能有一份信息,所以在那个方法中获取的信息都是一样的,第二次操作,存储的信息会把上一次操作存储的信息替换掉…
每一次事件触发,浏览器都会这样处理一下:
- 捕获到当前操作的行为(把操作信息获取到),通过创建 MouseEvent 等类的实例,得到事件对象 EV2. 通知所有绑定的方法(符和执行条件的)开始执行,并且把 EV 当作实参传递给每个方法,所以在每个方法中得到的事件对象其实是一个>
……3. 后面再重新触发这个事件行为,会重新获取本次操作的信息,用新的信息替换老的信息,然后继续之前的步骤…
let obj = null;
box.addEventListener('click', function (ev) {
console.log(ev);
obj = ev;
});
box.addEventListener('click', function (ev) {
console.log(ev === obj); // true
});
document.body.onclick = function (ev) {
console.log(ev === obj); // true
}
五、事件传播机制
事件的传播机制: 捕获阶段:从最外层向最里层事件源依次进行查找(目的:是为冒泡阶段事先计算好传播的层级路径) CAPTURING_PHASE:1 目标阶段:当前元素的相关事件行为触发 AT_TARGET:2 冒泡传播:触发当前元素的某一个事件行为,不仅它的这个行为被触发了,而且它所有的祖先元素(一直到window)相关的事件行为都会被依次触发(从内到外的顺序) BUBBLING_PHASE:3 (Event.prototype)
let $ = selector => document.querySelector(selector);
let inner = $('.inner');
let outer = $('.outer');
inner.onclick = function (e) {
console.log('inner 的click事件触发了');
};
outer.onclick = function (e) {
console.log('outer 的click事件触发了');
e.stopPropagation(); // 阻止事件冒泡
};
document.body.onclick = function () {
console.log('body 的click事件被触发了');
};
document.onclick = function () {
console.log('document 的click事件触发了');
};
事件冒泡
事件冒泡:我们点击 inner,inner 的父级元素 outer 的点击事件以及整个文档顶端的 document 的点击事件都会被依次触发。这种从低层级的 html 元素向高层级依次触发事件的现象称为事件冒泡;
取消冒泡:e.stopPropagation() 阻止事件冒泡;
IE 的阻止冒泡: e.cancelBubble = true;