网页上各种炫酷的交互效果离不开各种 DOM 事件 的支持,在写这篇文章之前,一度以为 JS 的事件绑定/取消方式就我知道的那几种,翻阅文档之后才发现,知识面还是有待提升,多翻翻文档,就像发现新大陆一样~~

常用事件

鼠标事件:

click:鼠标左键单击

dblclick:鼠标左键双击

mousedown / mouseup:鼠标按下/释放

mousemove:鼠标移动

mouseover / mouseout:鼠标移入/移出元素

mouseenter / mouseleave:鼠标移入/移出元素

contextmenu:鼠标右键点击时触发

wheel:鼠标滚轮滚动触发

键盘事件:

keydown / keyup:键盘按键按下/释放

窗口/文档事件:

DOMContentLoaded:HTML 解析完成

load:资源加载完成(如窗口、图片)

beforeunload / unload:窗口关闭前/后

resize:窗口大小变化

scroll:窗口滚动事件

动画事件:

animationstart / animationend:CSS 动画开始/结束

transitionstart / transitionend:CSS 过渡开始/结束

表单事件:

submit:表单提交

change:表单值变化(如输入框、下拉框)

input:输入时触发

focus / blur:元素获取/失去焦点

媒体事件:

play / pause:媒体播放/暂停

ended:媒体播放结束

timeupdate:播放时间更新

volumechange:音量变化

移动端事件:

touchstart:手指首次接触屏幕时触发

touchmove:手指在屏幕上滑动时连续触发

touchend:手指离开屏幕时触发

touchcancel:系统中断触摸时触发(如来电、弹窗)

devicemotion:检测设备加速度和旋转速率

deviceorientation:检测设备方向,多用于指南针或屏幕旋转

HTML5 新事件:

drag / drop:拖拽操作

copy / cut / paste:剪贴板操作

visibilitychange:页面可见性变化,比如浏览器 Tab 切换、浏览器最小化

hashchange:URL 哈希变化

popstate:浏览器历史变化(如前进/后退)

hashchangepopstate 在常规的开发中不太常用,但 Vue 和 React 中的路由底层可都是用它们实现的,前端单页应用能迅速的火爆起来,少不了它俩的功劳。


除了这些常用事件外,还有一些标签独有事件,比如 img 标签的 errorload 事件等。这里就不一一列举了,可阅读 MDN 文档获得更多信息。

MDN 事件文档:

https://developer.mozilla.org/zh-CN/docs/Web/Events

https://developer.mozilla.org/zh-CN/docs/Web/API/Element/copy_event

事件绑定

见过常用事件之后,再聊聊 JS 绑定事件的几种方式,以 click 事件为例。

最开始学习 JS 的时候,就用的是 HTML 标签属性的方式绑定事件,比如这样:

<!-- 所有的 HTML 事件属性都以 on 开头,比如 onclick onload onkeydown -->
<button onclick="handleClick()">这里是按钮</button>
<script>
function handleClick() {
alert('点击了按钮')
}
</script>

慢慢的学习之后发现这种方式有个弊端啊,handleClick 这个函数名定义在全局作用域之下,这东东可被称为 污染全局变量 了,后来就用上了这种方式:

<button id="button">这里是按钮</button>
<script>
(() => {
// 所有的事件属性都以 on 开头,比如 onclick onload onkeydown
document.querySelector('#button').onclick = () => {
alert('前端路引点击了按钮')
}
})()
</script>

这种方式虽然看起来没啥大问题,但是如果一个 DOM 节点绑定了两个相同的事件之后,只会执行最后一个绑定的方法,比如:

<button id="button2">这里是按钮</button>
<script>
(() => {
const btn = document.querySelector('#button2')
btn.onclick = () => {
alert('点击了按钮')
}
btn.onclick = () => {
alert('前端路引点击了按钮')
}
})()
</script>

还是存在弊端,如果团队合作的时候,有其他兄弟伙用这种方式绑定就完蛋了,所以后来又学到了一种新的方式:

<button id="button3">这里是按钮</button>
<script>
(() => {
const btn = document.querySelector('#button3')
// addEventListener 绑定的事件不需要添加 on 前缀
btn.addEventListener('click', () => {
alert('点击了按钮')
})
btn.addEventListener('click', () => {
alert('前端路引点击了按钮')
})
})()
</script>

嗯,这种绑定方式就完美了,在任何地方都可以绑定,还能一个事件多次绑定,也不存在全局污染。

取消绑定

有绑定事件,那必然就有取消绑定的需求。某些场景下,绑定的事件只需要执行一次,这种需求其实用一个变量也能实现,比如:

<button id="button4">这里是按钮</button>
<script>
(() => {
const btn = document.querySelector('#button4')
let isClicked = false
btn.addEventListener('click', () => {
if (isClicked) {
return
}
isClicked = true
alert('前端路引点击了按钮')
})
})()
</script>

再复杂一点,搞一个计数器,想限制多少次就限制多少,比如限制按钮只能点击五次:

<button id="button5">这里是按钮</button>
<script>
(() => {
const btn = document.querySelector('#button5')
let times = 0
btn.addEventListener('click', () => {
if (times >= 5) {
return
}
times++
alert('前端路引点击了按钮' + times)
})
})()
</script>

虽然这种方式也能满足需求,但与取消绑定的方式多少有点出入,还是聊聊取消绑定的几种方法。

使用 HTML 标签属性绑定的事件,可通过 removeAttribute 方法取消绑定:

<button onclick="handleClick(this)">这里是按钮</button>
<script>
function handleClick(el) {
alert('点击了按钮')
el.removeAttribute('onclick')
}
</script>

使用 onclick 绑定的事件,可通过将属性置空取消绑定:

<button id="button2">这里是按钮</button>
<script>
(() => {
const btn = document.querySelector('#button2')
btn.onclick = () => {
btn.onclick = undefined
alert('点击了按钮')
}
})()
</script>

使用 addEventListener 绑定的事件,可通过 removeEventListener 方法取消绑定:

<button id="button3">这里是按钮</button>
<script>
(() => {
const btn = document.querySelector('#button3')
function handleClick() {
alert('前端路引点击了按钮')
// 点击后移除事件
btn.removeEventListener('click', handleClick)
}
btn.addEventListener('click', handleClick)
})()
</script>

removeEventListener 第二个参数必须传入要移除的事件函数,否则方法报错!!

关于只执行一次的事件,也可以用 addEventListener 的第三个参数 once 来处理,比如:

<button id="button4">这里是按钮</button>
<script>
(() => {
const btn = document.querySelector('#button4')
btn.addEventListener('click', () => {
alert('前端路引点击了按钮')
}, { once: true })
})()
</script>

AbortController 移除事件

曾一度以为 AbortController 这个 API 仅用于终止 fetch 请求,后来发现也可以用于移除 DOM 事件,比如:

<button id="button5">这里是按钮</button>
<script>
(() => {
const btn = document.querySelector('#button5') const controller = new AbortController(); btn.addEventListener('click', () => {
alert('点击了按钮')
}, { signal: controller.signal }) btn.addEventListener('click', () => {
alert('前端路引点击了按钮')
// 移除所有通过此 signal 绑定的事件
controller.abort();
}, { signal: controller.signal })
})()
</script>

这个 API 的强大之处在于可一次性移除多个事件,嗯..比 removeEventListener 是要更加方便。

写在最后

虽然 Vue / React 中的 DOM 事件 框架已经整合优化,但某些需求场景还是免不了要使用原生的 DOM 事件,某个 Vue 组件元素要随窗口滚动而发生变化,这时候还是得靠原生的事件来实现。

Web前端入门第 73 问:JavaScript DOM 常用事件那点小事的更多相关文章

  1. web前端入坑第五篇:秒懂Vuejs、Angular、React原理和前端发展历史

    秒懂Vuejs.Angular.React原理和前端发展历史 2017-04-07 小北哥哥 前端你别闹 今天来说说 "前端发展历史和框架" 「前端程序发展的历史」 「 不学自知, ...

  2. Android零基础入门第73节:Activity初入门,创建和配置如此简单

    Activity是Android应用的重要组成单元之一,也是Android应用最常见的组件之一.前面看到的示例通常都只包含一个Activity或一个AppCompatActivity,但在实际应用中这 ...

  3. JavaScript Dom 绑定事件

    JavaScript  Dom 绑定事件 // 先获取Dom对象,然后进行绑定 document.getElementById('xx').onclick document.getElementByI ...

  4. Android零基础入门第36节:Android系统事件的响应

    原文:Android零基础入门第36节:Android系统事件的响应 在开发Android应用时,有时候可能需要让应用程序随系统设置而进行调整,比如判断系统的屏幕方向.判断系统方向的方向导航设备等.除 ...

  5. Javascript中常用事件集合和事件使用方法

    Javascript中常用事件集合和事件使用方法 一.事件绑定 格式: 事件源 . on事件类型=事件处理函数 事件绑定三要素 1.事件源:和谁绑定 2.事件类型:什么事件 3.事件处理函数:触发了要 ...

  6. web前端入坑第二篇:web前端到底怎么学?干货资料! 【转】

    http://blog.csdn.net/xllily_11/article/details/52145172 版权声明:本文为博主[小北]原创文章,如要转载请评论回复.个人前端公众号:前端你别闹,J ...

  7. web前端(13)—— 了解JavaScript,JavaScript的引入方式

    从本篇博文开始,将进入web前端方便最关键最重要的部分——javascript,学到后面你就知道它真的太重要了 什么是JavaScript JavaScript一种直译式的脚本语言,是一种动态类型.弱 ...

  8. Web前端基础怎么学? JavaScript、html、css知识架构图

    以前开发者只要掌握 HTML.CSS.JavaScript 三驾马车就能胜任一份前端的工作了.而现在除了普通的编码以外,还要考虑如何性能优化,如何跨端.跨平台实现功能,尤其是 AI.5G 技术的来临, ...

  9. WEB前端工程师整理的原生JavaScript经典百例

    一.原生JavaScript实现字符串长度截取 二.原生JavaScript获取域名主机 三.原生JavaScript转义html标签 四.原生JavaScript时间日期格式替换 Date.prot ...

  10. web前端学习之HTML CSS/javascript之一

    前端编码之路之坎坷,web前端应该一直是个战场吧,各种浏览器的不兼容,各种小细节的修改,要往一个好的产品经理方向走,实在是难,昨天听了一位十年经验的产品经理讲座,最重要的恐怕就是协调资源的能力,而协调 ...

随机推荐

  1. BUUCTF---BabyRSA(简单求解n)

    题目 p+q : 0x1232fecb92adead91613e7d9ae5e36fe6bb765317d6ed38ad890b4073539a6231a6620584cea5730b5af83a3e ...

  2. MySQL-排序相关原理分析

    全字段排序和rowId排序 建表语句如下: CREATE TABLE `t` ( `id` int(11) NOT NULL, `city` varchar(16) NOT NULL, `name` ...

  3. 【Java】修饰符

    修饰符(Modifier):是用于限定类型以及类型成员的声明的一种符号. 其用来定义类.方法或者变量,通常放在语句的最前端. 例子: public class Person { default Str ...

  4. 阿里巴巴暑期实习 Java 面经,灵犀互娱一面

    哈希表熟悉吗,可以如何实现? 开散列版本什么时候需要扩容 高并发服务器内的主从reactor模型是如何实现的? 进程 线程 协程 的区别? 如何保证线程安全 ? 了解读写锁吗? 单例模式有了解吗? 可 ...

  5. 0x03 搜索与图论

    搜索与图论 广度优先搜索\(BFS\) 概念 广度优先搜索(Breadth-First Search)是一种图遍历算法,用于在图或树中按层次逐层访问节点.它从源节点(起始节点)开始,首先访问源节点的所 ...

  6. redis的fd与epoll是怎么使用的

    Redis 的高性能网络模型核心依赖于 文件描述符(fd) 和 epoll 的协同工作.下面我将从底层机制到实际应用,详细解析它们的配合方式: 一.核心组件关系图 二.fd 在 Redis 中的具体应 ...

  7. ArrayBlockingQueue的poll方法底层原理

    一.ArrayBlockingQueue的poll方法底层原理 ArrayBlockingQueue 是 Java 并发包 (java.util.concurrent) 中的一个基于数组实现的有界阻塞 ...

  8. elemengui分页

    <!-- 分页模块 --> <template> <div class="block" style="margin-top:20px&quo ...

  9. Web前端入门第 35 问:CSS 细说 flex 弹性盒子布局(多图)

    flex 作为现代布局方案中最常用的手段,有必要拉出来细说. flex 相关的 CSS 属性 容器(父元素)相关的 CSS 属性 以下的 CSS 属性,在 flex 布局中需喂给父元素,设置 flex ...

  10. 判断属性值,选择性执行下一步(get element attribute指令的用法)

    应用场景: 下图线下支付,在退款前需要勾选这种支付方式,否则无法实现支付. 如果在测试脚本内即加入勾选指令,那么在下次执行的时候就会再次勾选,从而造成去除勾选的操作 对比一下勾选前后,勾选框元素内容组 ...