

JavaScript入门⑧-事件总结大全 - 安木夕
source link: https://www.cnblogs.com/anding/p/16890365.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.


JavaScript入门系列目录
01、事件基础
1.1、事件简介
事件(Event)是JavaScript的心脏,触发各种交互,让网页动起来。事件是浏览器网页可以监测到的行为,如页面加载、鼠标点击、键盘按键等。在这些事件中可以自定义事件处理程序,用于实现各种业务需求。

事件对象的继承关系:

常见的事件类型、事件如下:
⚡鼠标事件(event) | |
---|---|
click(event) | 点击触发,通常是鼠标左键在一个元素上被按下并放开时 |
dblclick | 双击触发事件 |
contextmenu | 鼠标右键点击触发 |
mousedown、mouseup | 鼠标按下、弹起时触发 |
mousemove | 鼠标在元素上移动时触发 |
onmouseover、mouseout | 鼠标移入、移出元素区域时触发 |
mouseenter、mouseleave | 鼠标移入、移出元素区域时触发,与上面不同的是不会冒泡 |
dragstart、dragend | 拖放事件(drag/dræɡ/拖) |
⚡键盘事件(event) | |
keydown、keyup | 键盘按键按下、松开时触发 |
⚡表单事件(event) | |
blur(event)、focusout() | 元素失去焦点,blur不会冒泡 (blue /blɜːr/ 模糊 /不乐/) |
focus、focusin | 元素获取焦点时触发,focus不会冒泡 |
from.submit | 提交表单form时触发,可用于表单校验 |
change | 值发生变化时触发,文本框是在值变化且失去焦点是才触发 |
input | 输入值改变时触发,event.preventDefault() 无法阻止,因为已经改变了 |
⚡Document 事件(event) | 文档生命周期:DOMContentLoaded ➡️ load ➡️ beforeunload ➡️ unload |
doc.DOMContentLoaded | 已加载 HTML并构建好DOM树,外部资源(image、css)可能尚未加载完成 - 如果遇到 <script> 标签,会执行(包括外部的资源)然后才继续后面的DOM加载,要注意!async、defer标记的除外(只支持外部js资源) |
window.load | 文档完全加载完成,包括图片、样式都准备好了。可用于window、element |
window.beforeunload | 当用户正在离开页面时,不可取消,好像也不能干什么。 |
window.unload | 用户几乎已经离开了,同上 |
doc.readystatechange | 文档状态变化时触发,可跟踪文档加载状态readyState |
onerror | 加载出现错误,用于元素 |
scroll | 滑动条滚动事件,具有滚动的视图元素。用于window、element |
⚡ClipboardEvent事件 | 事件参数对象clipboardData 由于安全限制,方法无法使用 |
cut,copy,paste | 剪切、拷贝、粘贴时触发 |
e.clipboardData | 保存了一个DataTransfer对象,用于存放数据,该对象也用于拖放 |
⚡CSS事件(event) | |
transitionend | 一个元素 CSS 动画完成时ele.addEventListener("transitionend", func) |
1.2、事件的绑定
① HTML事件:HTML中绑定(调用)事件处理程序,<button onclick="func(event);func2()">button</button>
,注意加括号()。
② JS绑定事件(DOM-0级事件):button.onclick = function() {}
,和HTML绑定一样,只能绑定一个事件处理程序。不能用setAttribute设置事件,因为设置的是字符串值。
③ 注册事件(DOM-2级事件):
- ele.addEventListener(event,func[, options]) :注册事件,👍推荐的常用方式,可添加多个事件处理程序,但同一个事件类型不可添加同一个handler对象。参数options为配置信息,如是否冒泡。
- ele.removeEventListener(event,func[, options]) :必须是与添加时相同(恒等)的参数,不可移除匿名函数事件。
④ 事件处理对象handleEvent
除了注册事件方法,还可用将一个包含handleEvent
方法的对象注册到事件处理程序,触发事件时调用对象的handleEvent
方法。so,只要对象中包含handleEvent
方法即可,任何对象、类的实例都可以。
<div id="ediv"> <span id="espan" onclick="console.log('html bind')">span</span> <button id="btn" onclick="console.log('html bind')">button</button></div><script> function func1(event) { console.log(event.currentTarget, event.target); //div span console.log("event.cancleable:" + event.cancelable) //event.cancleable:true console.log(event.clientX, event.clientY); //31 363 //取消冒泡 event.cancelBubble = true; event.stopPropagation(); event.stopImmediatePropagation(); //取消冒泡,以及元素同类型的其他事件 //取消默认事件,如checkbox,a元素的默认行为 event.preventDefault();//对自定义事件没用, } ediv.addEventListener('click', func1); ediv.addEventListener('click', e=>console.log(e.currentTarget.localName)); //div,前面取消了则不会执行 ediv.addEventListener('click', ()=>console.log('click me')); //事件处理对象,调用对象的handelEvent方法执行事件 let eventObj = { handleEvent(event) { console.log("handleEvent", this.objName, event); }, objName: "eventObj", } btn.addEventListener("click", eventObj);</script>
1.3、事件对象event
每一个事件处理程序都有一个event
对象,内置了事件的详细信息。最基础的Event如下,还有很多继承事件对象。
✅Event属性 | |
---|---|
type | 事件的类型 |
target | 指向事件触发的目标元素,可能为子元素,冒泡中不会改变。originalTarget为非标准(Mozilla) |
currentTarget = this | 指向事件绑定的元素,当前正在处理事假的元素,同 this 。 |
isTrusted | 触发方式,true=用户,false=脚本触发,(Trusted/ˈtrʌstɪd/ 可信的) |
bubbles | 判断事件是否冒泡,bool。( Bubble/ˈbʌb(ə)l/ 冒泡) |
cancelBubble✏️ | 是否取消冒泡,可设置true阻止冒泡,stopPropagation()的别名 |
composed | 表示事件是否可以穿过 Shadow DOM 和常规 DOM 之间的隔阂进行冒泡,bool |
event.clientX / clientY | 鼠标事件触发的x、y坐标 |
✅Event 方法 | |
stopPropagation() | 停止向上冒泡(propagation /ˌprɒpəˈɡeɪʃn/ 传播),不影响当前元素的其他注册事件 |
stopImmediatePropagation() | 取消后面的同类型事件的执行,包括冒泡,(Immediate /ɪˈmiːdiət/ 立刻) |
preventDefault() | 取消默认事件行为,如checkbox、<a> ,不影响冒泡。defaultPrevented 判断是否取消了 |
使用event.preventDefault()
可以移除浏览器的默认事件行为,也可以用return false
。
<p> <input type="checkbox" onclick="return false"> <!--取消默认事件行为:点击无效了--> <a href="http://www.qq.com" id="qq1" onclick="return false">QQ-1</a> <a href="http://www.qq.com" id="qq2">QQ-2</a> <a href="http://www.qq.com" id="qq3">QQ-3</a></p><script> //return false 对a标签好像没有作用 qq1.addEventListener("click", () => false); qq2.addEventListener("click", (event) => event.preventDefault()); //取消默认事件行为 qq3.addEventListener("click", (event) => { if (!confirm("你确定已满18周岁,要前往[ " + event.target.getAttribute("href") + " ] 吗?")) { event.preventDefault(); //取消默认事件行为 prevent /prɪˈvent/ 阻止 } });</script>
1.4、事件流:冒泡和捕获
事件的触发大都是某一个HTML元素,但这一个元素触发事件时,该事件会在该元素与根节点之间进行顺序传播,路过的元素都会接收到该事件,这个过程称为“事件流”,简单来说就是接收事件的顺序,如下三个阶段。
① 捕获阶段(Capturing phase):(phase /feɪz/ 阶段)
事件(从 Window)逐级向下传播,直到具体的目标元素。捕获阶段实际上很少使用,默认情况下也不会触发,addEventListener 注册事件时通过参数对象options.capture = true
设置在捕获阶段触发事件。ediv.addEventListener("click", fevent2, true /* { capture: true } */);
② 目标阶段(Target phase):事件到达目标元素。
❗目标元素
event.target
:直接触发事件的、最近的那个元素,也是嵌套最深的那个元素。
③ 冒泡阶段(Bubbling phase):一般常用的是冒泡阶段,这更符合逻辑。
事件从目标元素上开始冒泡,逐级向上春波,直到根节点。几乎所有事件都会冒泡,除了个别的,如blur
、focus
没有冒泡。

<div id="ediv"> <button id="ebutton">button</button></div><script> const eles = document.querySelectorAll("#ediv,#ebutton"); for (let ele of eles) { ele.addEventListener("click", e => console.log("capturing:" + e.currentTarget.localName), true); //捕获 ele.addEventListener("click", e => console.log("bubbling:" + e.currentTarget.tagName)); //冒泡 } /* capturing:div capturing:button bubbling:BUTTON bubbling:DIV */</script>
事件流的两种传播方式其实是IE和Netscape两个公司的不同处理机制导致的。
📢 停止冒泡:
stopPropagation()
、stopImmediatePropagation()
- 注意的区别,
stopPropagation()
只是停止向上冒泡;stopImmediatePropagation()
会额外取消当前元素同类型的后续事件。- 非必要不主动关闭冒泡,谨慎使用,可能会影响其他功能。
1.5、事件委托
事件委托只是事件的一种使用方式而已,基于事件冒泡在,上级节点统一处理从而简化事件的绑定。比如有一堆导航按钮,不需要每个都添加事件,把点击事件委托给其父级元素统一处理。
- 优点:简化代码逻辑,便于修改维护。
- 缺点:事件必须冒泡,如果被阻止了,就嗝屁了;可以忽略的冒泡性能损失。
表格排序示例(委托给表格统一处理):codePen地址
//需求:点击表格标题,对数据进行排序const table = document.querySelector("#grid");table.onclick = function (e) { //点击标题单元格,并且有自定义排序属性 if (e.target.tagName != "TH" || !e.target.hasAttribute("data-sort")) return; let th = e.target; sortTable(th.cellIndex, th.dataset.sort);};function sortTable(colIndex, type) { let trs = Array.from(document.querySelectorAll("#grid tbody tr")); let tbody = table.tBodies[0]; let sortFunc = function (r1, r2) { switch (type) { case "number": return r1.cells[colIndex].innerText - r2.cells[colIndex].innerText; break; case "number": default: return r1.cells[colIndex].innerText > r2.cells[colIndex].innerText? 1: -1; break; } }; trs = trs.sort(sortFunc); tbody.append(...trs); //追加已存在的元素,自动进行移动}
全局提示示例:点击查看【codepen】
1.6、自定义事件
① 创建事件对象:let event = new Event(type[, options])
,使用Event构造函数,或者CustomEvent
自定义事件(参数中有一个detail
字段可存放自定义数据,在事件处理程序中通过event.detail
使用),或其他事件对象MouseEvent、KeyboardEvent。
- type:事件类型,可以是像 "click" 这样的字符串或任意。
- options:具有两个可选属性的对象,是否冒泡
bubbles
(true=冒泡、false),是否取消默认行为ancelable
: (true=阻止、false),默认值都是false。
②触发事件:elem.dispatchEvent(event)
在你需要的地方调用elem.dispatchEvent(event)
触发自定义事件,事件的处理程序和普通事件一样通过addEventListener
添加,不支持on***
。
<p> <input type="text" id="input"></p><script> //1、定义事件:当按下F4按钮时触发 let keyF4Click = new CustomEvent("keyF4Click", { detail: { key: "F4" } }) input.addEventListener("keyup", (event => { if (event.key == "F4") //2、触发事件 input.dispatchEvent(keyF4Click); })) //只能通过addEventListener添加自定义的事件处理程序 input.addEventListener("keyF4Click", (e) => { input.value += e.detail.key; })</script>
02、UI事件⚡
2.2、鼠标事件MouseEvent
鼠标事件(event) | |
---|---|
click(event) | 点击触发,通常是鼠标左键在一个元素上被按下并放开时 |
dblclick | 双击触发事件 |
contextmenu | 鼠标右键点击触发 |
mousedown、mouseup | 鼠标按下、弹起时触发 |
mousemove | 鼠标在元素上移动时触发 |
onmouseover、mouseout | 鼠标移入、移出元素区域时触发 |
mouseenter、mouseleave | 鼠标移入、移出元素区域时触发,与上面不同的是不会冒泡 |
dragstart、dragend | 拖放事件(drag/dræɡ/拖) |
鼠标事件响应顺序:mouseenter
→ mousemove
→ mousedown
→ mouseup
→ click
→ mouseleave
<button id="btn" >button</button><script> btn.addEventListener("mouseenter", (e)=>console.log(1,e.type)); //1 'mouseenter' btn.addEventListener("mousemove", (e)=>console.log(2,e.type)); //2 'mousemove' btn.addEventListener("mousedown", (e)=>console.log(3,e.type)); //3 'mousedown' btn.addEventListener("mouseup", (e)=>console.log(4,e.type)); //4 'mouseup' btn.addEventListener("click", (e)=>console.log(5,e.type)); //5 'click' btn.addEventListener("mouseleave", (e)=>console.log(6,e.type)); //6 'mouseleave'</script>
MouseEvent属性 | |
---|---|
button | 鼠标按下的按钮:0=主按键/左键,1=滚轮中按键,2=次按键/右键 |
clientX / clientY | 鼠标指针在窗口的 X 坐标、Y 坐标 |
pageX/pageY | 鼠标指针在文档的 X 坐标、Y 坐标 |
ctrlKey、altKey、shiftKey | 是否按下了Ctrl 、Alt 、Shift 按键,bool值 |
metaKey | Mac中的 Cmd,同window的Ctrl |
relatedTarget | 次要(关联)目标,鼠标移入/出中使用,表示上一个target |
鼠标点击位置动画示例:codepen
<style> .mpoint { position: absolute; padding: 0; margin: 0; width: 200px; height: 200px; background-color: #dda427; border-radius: 50%; animation: click 1s; } @keyframes click { 0% { transform: scale(0, 0); opacity: 0; } 30% { transform: scale(1, 1); opacity: 1; } 100% { transform: scale(0, 0); background-color: #7c20e4; opacity: 0; } }</style><script> let cdiv = document.createElement('div'); //动画执行完后移除自身 cdiv.addEventListener('animationend', () => cdiv.remove()); window.addEventListener('click', (e) => { document.body.append(cdiv); cdiv.className = 'mpoint'; //定位圆圈的位置,为鼠标点坐标 cdiv.style.left = (e.clientX - cdiv.clientWidth / 2) + 'px'; cdiv.style.top = (e.clientY - cdiv.clientHeight / 2) + 'px'; });</script>
2.3、键盘事件KeyboardEvent
键盘事件(event) | |
---|---|
keydown、keyup | 键盘按键按下、松开时触发 |
过时的keypress |
KeyboardEvent属性 | |
---|---|
code | 按键编码(KeyA、KeyA、F1、0、Shift),物理按键的准确编码,比较稳定 |
key | 按键值(A、a、F1、Digit0、ShiftLeft),正常看到的值,可能会随系统语言、输入环境变化 |
repeat | 按键是否被一直按住,bool。按住时会一直触发keydown |
ctrlKey、altKey、shiftKey | 是否按下了Ctrl 、Alt 、Shift 按键,bool值 |
metaKey | Mac中的 Cmd,同window的Ctrl |
03、表单事件⚡
3.1、表单查找/取值
🔸获取表单<form>
,<form name="formName">
除了元素查找还有如下方式
- 属性访问:
document.formName
, - forms属性:
document.forms
为文档中所有表单集合。
<form name="loginForm"><input type="text"></form><script> document.loginForm; document.forms.loginForm; document.forms['loginForm']; document.forms[0];</script>
🔸获取表单元素:
form.name
form.elements
集合,不用管元素的层级- form.elements.name,单个元素
- form.elements['name'],元素名为
name
的集合,组合元素使用。
- 子表单
fieldset.elements
❗表单和表单元素的双向引用:
🔸表单元素取值:input.value,<input>
表单元素大部分都是value
取值/赋值,注意下面的:
- input.checked,单选
radio
、多选checkbox
通过checked
取值/赋值,多个需要遍历取值。 - textarea.value,⚠️注意多行文本
<textarea>
是通过value
取值,而不是innerHTML
。 - 下拉框select:select.options =
<option>
的子元素的集合- 单选:
select.value
、select.selectedIndex
- 多选:遍历
options
取值,Array.from(select.options).filter(op=>op.select).map(op=>op.value);
- 单选:
🔸提交表单:
- document.loginForm.submit():表单的
submit()
方法提交,完全自主控制,推荐食用。 - submit按钮+事件onclick=return 校验函数():校验函数校验表单数据,返回true提交表单,否则不提交
<button type="submit" onclick="return canSubmit()">
- submit按钮+form的事件onsubmit=return 校验函数():功能和用法基本同上。
<form name="fuser" id="fuser" action="" method="post"> 姓名:<input name="userName" type="text" title="请输入用户名" /><br /> 密码:<input name="userPwd" type="password" title="请输入密码" /><br /> 生日:<input name="userBirthday" type="date" value="2021-10-11" /><br /> 性别:<input name="sex" id="usex1" type="radio" value="男" checked=true /><label for="usex1">男</label> <input name="sex" id="usex2" type="radio" value="女" /><label for="usex2">女</label> <input name="sex" id="usex3" type="radio" value="其他" /><label for="usex3">其他</label><br /> 爱好:<input id="uint1" name="interest" type="checkbox" value="运动" /><label for="uint1">运动</label> <input id="uint2" name="interest" type="checkbox" value="学习" /><label for="uint2">学习</label> <input id="uint3" name="interest" type="checkbox" value="看书" /><label for="uint3">看书</label> <input id="uint4" name="interest" type="checkbox" value="躺着" /><label for="uint4">躺着</label><br /> 学历:<select id="education" name="education"> <option value="大专">大专</option> <option value="本科">本科</option> <option value="研究生">研究生</option> </select><br /> <button type="button" onclick="getData()">获取数据</button></form>

<script> var form = document.fuser;function getData() { var form = document.fuser; var userData = {}; userData.userName = form.userName.value; userData.userPwd = form.userPwd.value; userData.userBirthday = form.userBirthday.value; //单选、多选,注意设置name、value值,遍历取值 userData.sex = Array.from(document.getElementsByName('sex')) .filter(n => n.checked)[0]?.value userData.interest = Array.from(document.getElementsByName('interest')) .filter(n => n.checked).map(n=>n.value).join(); //下拉框取值 userData.education = form.education.value; userData.education = form.education.options[form.education.selectedIndex].value; console.log(JSON.stringify(userData));};getData();</script>
3.2、表单事件
✅表单事件(event) | |
---|---|
blur(event)、focusout() | 元素失去焦点,blur不会冒泡 (blue /blɜːr/ 模糊 /不乐/) |
focus、focusin | 元素获取焦点时触发,focus不会冒泡 |
from.submit | 提交表单form时触发,可用于表单校验 |
change | 值发生变化时触发,文本框是在值变化且失去焦点是才触发 |
input | 输入值改变时触发。event.preventDefault()无法阻止,因为已经改变了 |
✅方法-聚焦 | |
elem.focus() | 设置元素获得焦点 |
elem.blur() | 设置元素失去焦点 |
可编辑单元格的表格示例:codepen
©️版权申明:版权所有@安木夕,本文内容仅供学习,欢迎指正、交流,转载请注明出处!原文编辑地址-语雀
Recommend
-
4
00、 引言 作为一名IT码农,入行十载有余,写的代...
-
12
01、 健康饮食很重要 1.1、健康...
-
8
什么是枚举Enum 枚举 Enum是在众多语言中都有的一种数据类型,JavaScript中还没有(TypeScript有)。用来表示一些特定类别的常量数据,如性别、学历、方向、账户状态等,项目开发中是很常用的。
-
32
01、<form>表单
-
3
01、JavaScript基础知识 JavaScript(缩写:JS)是一种...
-
5
01、什么是Vuex? 1.1、为什么需要状...
-
5
VSCode(Visual Studio Code)是一款开源、跨平台、轻量级的代码编辑器,具有非常...
-
8
01、防抖还是节流 防抖 与 ...
-
6
冒泡排序(Bubble Sort)算是前端最简单的算法,也是最经典的排序算法了。网上JavaScr...
-
5
01、为什么要跨域? 跨域的根本原因是浏览器的“同源策...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK