一、什么是"事件监听"
- 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
来表示。jsoBox.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>
元素就变红。html<!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>
元素就变红html<!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
事件处理程序附加到的元素 html<!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都表示"鼠标进入",它们有什么区别呢?