1. 事件基础
JavaScript可以让我们创建动态页面,而事件是可以被 JavaScript 侦测到的行为。简单理解事件就是: 触发--- 响应机制。
网页中的每个元素都可以产生某些可以触发 JavaScript 的事件,例如,用户点击某按钮时产生一个 事件,然后去执行某些操作。
1.1 事件三要素
① 事件源 (谁)
② 事件类型 (什么事件)
③ 事件处理程序 (做啥事)
1.2 案例解析
<body> <button>点击</button> <script> // 事件三要素 // 1. 获取元素(即为事件源) let btn = document.querySelector("button"); // 2. 绑定事件(这里绑定的是点击事件) btn.onclick = function() { // 3. 事件处理程序(这里为弹出alert 警示框) alert("今天天气真好!") }; </script> </body>
对此案例进行分析,可知其事件三要素如下:
① 获取事件源(按钮)
② 注册事件(绑定事件),使用 onclick(点击事件)
③ 编写事件处理程序,写一个函数弹出 alert 警示框
1.3 执行事件的步骤
① 获取事件源
② 注册事件(绑定事件)
③ 添加事件处理程序(采取函数赋值形式)
1.4 常见的鼠标事件
1.5 mouseover和mouseenter的区别
<body> <div> <span>我是鼠标移入over</span> </div> <div> <span>我是鼠标进入enter</span> </div> <script> // 1.获取元素(事件源) let divs = document.querySelectorAll('div'); // 定义变量i,让其在鼠标移入后进行自加 let i = 0; // 2.绑定事件(鼠标移入事件) divs[0].onmouseover = function() { // 3.事件处理程序 let spans = document.querySelectorAll('span'); spans[0].innerHTML = i++; }; // 定义变量j,让其在鼠标进入后进行自加 let j = 0; // 2.绑定事件(鼠标移入事件) divs[1].onmouseenter = function() { // 3.事件处理程序 let spans = document.querySelectorAll('span'); spans[1].innerHTML = j++; } </script> </body>
通过该案例可以得知:
① onmouseover事件,不仅鼠标经过自身盒子会触发,而且经过子节点的时候也会触发;
② 而onmouseenter事件,鼠标只有经过自身盒子才会触发,经过子节点的时候不触发,原因是mouseenter不会冒泡
③ onmouseout和onmouseover是一对,所以同样经过子节点会触发事件,而onmouseleave和onmouseenter是一对,所以其一样不会冒泡。
2. 事件高级
2.1 注册事件(绑定事件)
给元素添加事件,称为注册事件或者绑定事件。注册事件有两种方式:传统方式和方法监听注册方式 。
(1)传统注册方式
① 利用 on 开头的事件,如 onclick
② 使用语法: eventTarget.onclick = function() {}
③ 特点: 注册事件的唯一性
④ 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数;
(2)方法监听注册方式
① w3c 标准 推荐方式
② addEventListener() 它是一个方法
③ 特点:同一个元素同一个事件可以注册多个监听器,并按注册顺序依次执行
语法:eventTarget.addEventListener(type, listener, [useCapture])
eventTarget.addEventListener()方法将指定的监听器注册到 eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数。
该方法接收三个参数:
① type:事件类型字符串,比如 click 、mouseover ,注意这里不要带 on
② listener:事件处理函数,事件发生时,会调用该监听函数
③ useCapture:可选参数,是一个布尔值,默认是 false,false表示处于冒泡阶段,true表示处于捕获阶段。
2.2 删除事件(解绑事件)
(1)传统注册方式
eventTarget.onclick = null; // 移除目标对象上的点击事件
(2)方法监听注册方式
// 删除绑定事件,事件处理函数有可能被移除,那么在使用方法监听注册时就不要使用匿名函数 eventTarget.removeEventListener('事件类型', 原处理函数); 比如: <button>监听绑定事件方式</button> <script> let btn = document.querySelector('button'); // 注册事件时给处理函数命名为fun btn.addEventListener('click', function fun() { console.log(8765); // 删除事件时,直接使用fun即可 btn.removeEventListener('click', fun) })
2.3 DOM事件流
所谓事件流描述的是从页面中接收事件的顺序。而DOM 事件流,指的是事件发生时,在元素节点之间按照特定顺序传播的过程 。
DOM 事件流分为3个阶段:
① 捕获阶段
② 当前目标阶段
③ 冒泡阶段
(1)事件捕获: 网景最早提出,由 DOM 最顶层节点开始,然后逐级向下传播到到最具体元素接收的过程。 即由外向内,依次记录各级元素上绑定的处理函数,只记录,不执行
(2)事件冒泡: IE 最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点的过程。即由内向外,依次触发捕获阶段记录的各级父元素上的处理函数。
注意:
1. JS 代码中只能执行捕获或者冒泡其中的一个阶段。
2. onclick只能得到冒泡阶段。
3. addEventListener(type, listener, [useCapture])第三个参数如果是 true,表示在事件捕获阶段调用事件处理程序;如果是 false(不写默认就是false),表示在事件冒泡阶段调用事件处理
程序。
4. 实际开发中我们很少使用事件捕获,我们更关注事件冒泡。
5. 有些事件是没有冒泡的,比如 onblur、onfocus、onmouseenter、onmouseleave
2.4 事件对象
所谓事件对象就是:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象 event,它有很多属性和方法。
(1)事件对象的使用语法
eventTarget.onclick = function(event) { // 这个 event 就是事件对象,我们还喜欢写成 e 或者 ev } eventTarget.addEventListener('click', function(event) { // 这个 event 就是事件对象,我们还喜欢写成 e 或者 ev })
这个 event 是个形参,系统帮我们设定为事件对象,不需要传递实参过去。
当我们注册事件时, event 对象就会被系统自动创建,并依次传递给事件监听器(事件处理函数)。
(2)事件对象的兼容性方案
事件对象本身的获取存在兼容问题:
1. 标准浏览器中是浏览器给方法传递的参数,只需要定义形参 e 就可以获取到。
2. 在 IE6~8 中,浏览器不会给方法传递参数,如果需要的话,需要到 window.event 中获取查找。
解决方案: e = e || window.event;
(3)事件对象的常见属性和方法
e.target 和 this 的区别:
① this 是事件绑定的元素, 这个函数的调用者(绑定这个事件的元素)
② e.target 是事件触发的元素。
2.5 阻止事件冒泡
事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点。
事件冒泡本身的特性,会带来的坏处,也会带来的好处,需要我们灵活掌握。
阻止事件冒泡的标准写法:
// 利用事件对象里面的 stopPropagation()方法 e.stopPropagation()
2.6 事件委托(代理、委派)
因为浏览器触发事件时采用的是遍历队列的方式,队列中监听的对象多,遍历查找的就慢,事件响应的速度就可能延迟。而利用事件冒泡本身的特性进行事件委托,则可以减少监听对象,从而提升了响应速度。
事件委托的原理:不是每个子节点单独设置事件监听器,而是把事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点,用e.target代替this获得目标元素。
<body> <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> </ul> <script> // 事件委托的核心原理:给父节点添加监听器,利用事件冒泡影响每一个子节点 // 获取父元素ul let ul = document.querySelector('ul'); // 给父元素注册监听事件 ul.addEventListener('click', function(e) {; // e.target 表示我们触发的对象 // 目标元素必须经过判断,符合条件,才能指向后续操作 if (e.target.nodeName == 'LI') { e.target.style.backgroundColor = 'pink'; } }) </script> </body>
点击每个 li 都会将其自身的背景色改为粉色,以前需要给每个 li 注册事件,访问 DOM 的次数越多,这就会延长整个页面的交互就绪时间。
而使用事件委托,则只需要给他们的父元素ul注册一次事件即可,利用冒泡特性实现这一需求,由于只操作了一次 DOM ,所以提高了程序的性能。
因此,当多个平级子元素都要绑定相同的事件时,只要将事件在父元素绑定一次就行,所有的子元素都可通过冒泡原理共享父元素的事件使用 。
2.7 常用的鼠标事件
event对象代表事件的状态,跟事件相关的一系列信息的集合。现阶段我们主要是用鼠标事件对象
MouseEvent 和键盘事件对象 KeyboardEvent。
2.8 常用的键盘事件
(1)常用键盘事件
事件除了使用鼠标触发,还可以使用键盘触发。
注意:
1. 如果使用addEventListener 不需要加 on
2. onkeypress 和前面2个的区别是,它不识别功能键,比如左右箭头,shift 等。
3. 三个事件的执行顺序是: keydown -- keypress --- keyup.
(2)键盘事件对象
注意:
1. onkeydown 和 onkeyup 不区分字母大小写,onkeypress 区分字母大小写。
2. 在我们实际开发中,我们更多的使用keydown和keyup, 它能识别所有的键(包括功能键)
3. keypress 不识别功能键,但是keyCode属性能区分大小写,返回不同的ASCII值.
(3)ASCII 表
本文主要介绍理论知识,下篇文章则会在此基础上进行项目实操。