事件流
通常,一个事件会从父元素开始向目标元素传播,然后它将被传播回父元素。
JavaScript 事件分为三个阶段:
- 捕获阶段:事件从父元素开始向目标元素传播,从
Window
对象开始传播。 - 目标阶段:该事件到达目标元素或开始该事件的元素。
- 冒泡阶段:这时与捕获阶段相反,事件向父元素传播,直到
Window
对象。
如下图事件传播过程:
事件捕获
目标处理程序被调用之前的阶段,叫捕获阶段。
捕获阶段: 最先调用的是 Window对象上注册的捕获处理程序,然后调用 Document对象的捕获处理程序,接着是 <body>元素,沿着 DOM树一直向下,直到事件目标元素的捕获事件处理程序被调用。
事件捕获提供了 把事件发送到目标之前先行处理的机会,可用于调试。
冒泡阶段: 注册在元素上的事件处理程序被调用后,多数事件都会沿着 DOM树向上“冒泡”,但到Document对象就会停止冒泡,不会传播到 Window对象。
js中 注册事件处理程序
有两种注册事件处理程序的方式,第一种是web早期就有的,及设置作为事件目标的对象或者文档的一个属性。第二中就是把处理程序传给这个对象或者元素的 addEventListener()方法。
JavaScript 设置事件处理程序属性
最简单的方法就是把事件目标的一个属性设置为关联的事件处理程序函数。比如 form表单有 onsubmit提交事件,现在把 onsubmit 这个处理事件程序重写成其他的功能处理程序。
// 这个事件的处理车徐会在文档加载完成时被调用
window.load = function() {
let form = document.querySelector("#form");
form.onsubmit = function (event){ // 用户提交表单时触发
if(!isFormValid(this)) { // 检查表单验证是否通过
event.preventDefault(); // 阻止提交
}
}
}
这种方法假设事件目标对每种事件最多只有一个处理程序,一般不会使用吧
HTML设置事件处理程序属性
文档元素的事件处理程序 属性也可以直接在html 文件中作为对应HTML标签的属性来定义。
在使用 html属性定义事件处理程序时,属性值应该是一段JavaScript代码字符串,这段代码是事件处理程序函数的函数体,不是完整的函数声明,没有 function关键字。
<button onclick="console.log('Tank you!!!);">Click me</button>
这里的函数体需用 分号分隔每个语句,或者用回车分成对行。
浏览器会把这个字符串转成一个函数,
function(event) {
width(document) {
with(this.form || {} ) {
with(this) {
console.log('Thank you!!!'); // 你的代码
}
}
}
}
width 语句可以让处理程序直接引用目标的对象,比如 form有很多属性,使用 width(form) {},函数体里面可以直接使用 form属性,不用加上对象实例名和“.” 。
addEventListener() 监听事件
如以下代码:addEventListener()监听 click事件,不会影响 onclick的属性值,所以点击 button 时两个方法都会被调用,按注册的顺序调用。(一个事件目标可能会为一种事件注册多个处理程序,浏览器会按照注册处理程序的顺序调用 )
<body>
<div id="app">
<button id="bnt">cllick me</button>
</div>
<script>
let b = document.querySelector('#bnt');
b.onclick = function() {
console.log('click me!!!!!!');
}
b.addEventListener('click', () => {
console.log('again click!!');
})
</script>
</body>
与之对应的是 移除监听事件 removeEventListener()
事件取消
事件取消可以阻止浏览器的默认事件比如点击一个链接时,浏览器跟随链接。
<a href="http://baidu.com">baidu.com</a>
let a = document.querySelector('a');
a.onclick= (event) => {
// event.preventDefault(); // 取消默认事件
event.stopPropagation();// 取消事件传播
}
preventDefault()可执行 事件取消 ,以上代码 就是取消了 浏览器 跟随 a链接的 事件。
事件派发
事件派发可以把一些需要传递复杂数据的复杂的代码 解耦;
vue 中的 $on 、$emit、$off这些也是事件派发
js 原生实现:
自定义派发事件(触发事件): CustomEvent 创建自定义事件
document.dispatchEvennt(new CustomEvent('busy',{details: true}));
事件监听:
document.addEventListener('busy' (e) => {
if(e.detail) {
// 处理程序代码
} else {
// 处理程序代码
}
});