一、什么是"事件监听"
- DOM允许书写JavaScript代码以让HTML元素对事件作出反应
- 什么是"事件": 用户与网页的交互动作
- 当用户点击元素时
- 当鼠标移动到元素上时
- 当文本框的内容被改变时
- 当键盘在文本框中被按下时
- 当网页已加载完毕时
- …
-
“监听”,顾名思义,就是让计算机
随时能够发现这个事件发生了
,从而执行程序员预先编写的一些程序。 -
设置事件监听的方法主要有
onxxx
和addEventListener()
两种, -
常见的鼠标事件监听
事件名 事件描述 onclick
当鼠标单击某个对象 ondblclick
当鼠标双击某个对象 onmousedown
当某个鼠标按键在某个对象上被按下 onmouseup
当某个鼠标按键在某个对象上被松开 onmousemove
当某个鼠标按键在某个对象上被移动 onmouseenter
当鼠标进入某个对象(相似事件onmouseover) onmouseleave
当鼠标离开某个对象(相似事件onmouseout) -
常见的键盘事件监听
事件名 事件描述 onkeypress
当某个键盘的键被按下(系统按钮如箭头键和 功能键无法得到识别) onkeydown
当某个键盘的键被按下(系统按钮可以识别, 并且会先于onkeypress发生) onkeyup
当某个键盘的键被松开 -
常见的表单事件监听
事件名 事件描述 onchange
当用户改变域的内容 onfocus
当某元素获得焦点(比如tab键或鼠标点击) onblur
当某元素失去焦点 onsubmit
当表单被提交 onreset
当表单被重置 oninput
当表单输入 -
常见的页面事件监听
事件名 事件描述 onload
当页面或图像被完成加载 onunload
当用户退出页面
二、事件传播
-
事件的传播是:
先从外到内,然后再从内到外
-
onxxx
写法和addEventListener()
方法区别onxxx
写法只能监听冒泡阶段
,DOM0级事件监听。addEventListener()
,通过参数控制,可以监听捕获或者冒泡,DOM2级事件监听。
-
注意:
最内部元素不再区分捕获和冒泡阶段
,会先执行写在前面的监听,然后执行后写的监听。- 如果给元素设置相同的两个或多个同名事件,则DOM0级写法后面写的会覆盖先写的;而DOM2级会按顺序执行。
三、事件对象
-
事件处理函数提供一个形式参数,它是一个对象,
封装了本次事件的细节
-
这个参数通常用
单词event或字母e
来表示。oBox.onmousemove = function (e) { // 对象e就是这次事件的"事件对象" }
-
鼠标位置
属性 属性描述 clientX
鼠标指针相对于 浏览器
的水平坐标clientY
鼠标指针相对于 浏览器
的垂直坐标pageX
鼠标指针相对于 整体网页
的水平坐标pageY
鼠标指针相对于 整体网页
的垂直坐标offsetX
鼠标指针相对于 事件源元素
的水平坐标offsetY
鼠标指针相对于 事件源元素
的垂直坐标
-
e.charCode
和e.keyCode
属性e.charCode
属性通常用于onkeypress
事件中,表示用户输入的字符的"字符码"。e.keyCode
属性通常用于onkeydowm
事件中和onkeyup
中,表示用户按下的按键的"键码"。
-
charCode
字符码字符 字符码 数字0~数字9
48~57 大写字母A~Z
65~90 小写字母a~z
97~122 -
keyCode
键码按键 键码 数字0~数字9
48~57 字母不分大小a~z
65~90 四个方向键左、上、右、下
37、38、39、40 回车键
13 空格键
32 -
e.preventDefault()
方法e.preventDefault()
方法用来阻止事件产生的"默认动作"
。
-
e.stopPropagation()
方法
-e.stopPropagation()
方法用来阻止事件继续传播- 一些场合,非常有必要切断事件继续传播,否则会造成页面特效显示bug。
四、事件委托
批量添加事件监听
题目:页面上一个无序列表
<ul>
,它内部共有20个<li>
元素,请批量给它们添加点击事件监听,实现效果:点击哪个
<li>
元素,哪个<li>
元素就变红。<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <ul id="list"> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> <li>列表项</li> </ul> <script> var oList = document.getElementById('list'); var lis = oList.getElementsByTagName('li'); // 书写循环语句,批量给元素添加监听 for (var i = 0; i < lis.length; i++) { lis[i].onclick = function () { // 在这个函数中,this表示点击的这个元素,this涉及函数上下文的相关知识,我们在“面向对象”课程中介绍 this.style.color = 'red'; }; } </script> </body> </html>
-
批量添加事件监听的性能问题
- 每一个事件监听注册都会消耗一定的系统内存,而批量添 加事件会导致监听数量太多,
内存消耗会非常大
。 - 实际上,
每个<li>的事件处理函数都是不同的函数
,这些函数本身也会占用内存。
- 每一个事件监听注册都会消耗一定的系统内存,而批量添 加事件会导致监听数量太多,
-
新增元素动态绑定事件
题目:页面上有一个无序列表
<ul>
,它内部没有<li>元素
, 请制作一个按钮,点击这个按钮就能增加一个<li>
元素。
并且要求每个增加的<li>元素也要有点击事件监听
,实现效果 点击哪个<li>
元素,哪个<li>
元素就变红<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <button id="btn">按我添加新的li列表项</button> <ul id="list"></ul> <script> var oBtn = document.getElementById('btn'); var oList = document.getElementById('list'); var lis = oList.getElementsByTagName('li'); // 按钮的点击事件 oBtn.onclick = function () { // 创建一个新的li列表项,孤儿节点 var oLi = document.createElement('li'); oLi.innerHTML = '我是列表项'; // 上树 oList.appendChild(oLi); // 给新创建的这个li节点添加onclick事件监听 oLi.onclick = function () { this.style.color = 'red'; }; }; </script> </body> </html>
- 动态绑定事件的问题
- 新增元素必须分别添加事件监听,
不能自动获取事件监听
。 - 大量事件监听、大量事件处理函数会
产生大量内存消耗
。
- 新增元素必须分别添加事件监听,
- 动态绑定事件的问题
-
事件委托
-
利用
事件冒泡
机制,将后代元素
事件委托给祖先元素
。 -
事件委托通常需要结合使用
e.target
属性参数 描述 target
触发此事件的最早元素,即"事件源元素" currentTarget
事件处理程序附加到的元素 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <button id="btn">按我创建一个新列表项</button> <ul id="list"> <li>列表项</li> <li>列表项</li> <li>列表项</li> </ul> <script> var oList = document.getElementById('list'); var oBtn = document.getElementById('btn'); oList.onclick = function (e) { // e.target表示用户真正点击的那个元素 e.target.style.color = 'red'; }; oBtn.onclick = function () { // 创建新的li元素 var oLi = document.createElement('li'); // 写内容 oLi.innerText = '我是新来的'; // 上树 oList.appendChild(oLi); }; </script> </body> </html>
-
-
事件委托的使用场景
当有大量类似元素需要批量添加事件监听时
,使用事件委 托可以减少内存开销。当有动态元素节点上树时
,使用事件委托可以让新上树的 元素具有事件监听
-
使用事件委托时需要注意的事项
- onmouseenter和onmouseover都表示"鼠标进入",它们有什么区别呢?
onmouseenter不冒泡
,onmouseover冒泡
。
- 使用事件委托时要注意:
不能委托不冒泡的事件给祖先元素
。 - 最内层元素不能再有额外的内层元素了。
- onmouseenter和onmouseover都表示"鼠标进入",它们有什么区别呢?