天天食府 發表於 2025-6-30 10:18:00

Web前端入门第 73 问:JavaScript DOM 常用事件那点小事

<p>网页上各种炫酷的交互效果离不开各种 <code>DOM 事件</code> 的支持,在写这篇文章之前,一度以为 JS 的事件绑定/取消方式就我知道的那几种,翻阅文档之后才发现,知识面还是有待提升,多翻翻文档,就像发现新大陆一样~~</p>
<h2 id="常用事件">常用事件</h2>
<p><strong>鼠标事件:</strong></p>
<p>click:鼠标左键单击<br>
dblclick:鼠标左键双击<br>
mousedown / mouseup:鼠标按下/释放<br>
mousemove:鼠标移动<br>
mouseover / mouseout:鼠标移入/移出元素<br>
mouseenter / mouseleave:鼠标移入/移出元素<br>
contextmenu:鼠标右键点击时触发<br>
wheel:鼠标滚轮滚动触发</p>
<p><strong>键盘事件:</strong></p>
<p>keydown / keyup:键盘按键按下/释放</p>
<p><strong>窗口/文档事件:</strong></p>
<p>DOMContentLoaded:HTML 解析完成<br>
load:资源加载完成(如窗口、图片)<br>
beforeunload / unload:窗口关闭前/后<br>
resize:窗口大小变化<br>
scroll:窗口滚动事件</p>
<p><strong>动画事件:</strong></p>
<p>animationstart / animationend:CSS 动画开始/结束<br>
transitionstart / transitionend:CSS 过渡开始/结束</p>
<p><strong>表单事件:</strong></p>
<p>submit:表单提交<br>
change:表单值变化(如输入框、下拉框)<br>
input:输入时触发<br>
focus / blur:元素获取/失去焦点</p>
<p><strong>媒体事件:</strong></p>
<p>play / pause:媒体播放/暂停<br>
ended:媒体播放结束<br>
timeupdate:播放时间更新<br>
volumechange:音量变化</p>
<p><strong>移动端事件:</strong></p>
<p>touchstart:手指首次接触屏幕时触发<br>
touchmove:手指在屏幕上滑动时连续触发<br>
touchend:手指离开屏幕时触发<br>
touchcancel:系统中断触摸时触发(如来电、弹窗)</p>
<p>devicemotion:检测设备加速度和旋转速率<br>
deviceorientation:检测设备方向,多用于指南针或屏幕旋转</p>
<p><strong>HTML5 新事件:</strong></p>
<p>drag / drop:拖拽操作<br>
copy / cut / paste:剪贴板操作<br>
visibilitychange:页面可见性变化,比如浏览器 Tab 切换、浏览器最小化<br>
hashchange:URL 哈希变化<br>
popstate:浏览器历史变化(如前进/后退)</p>
<p><code>hashchange</code> 和 <code>popstate</code> 在常规的开发中不太常用,但 Vue 和 React 中的路由底层可都是用它们实现的,前端单页应用能迅速的火爆起来,少不了它俩的功劳。</p>
<hr>
<p>除了这些常用事件外,还有一些标签独有事件,比如 img 标签的 <code>error</code> 和 <code>load</code> 事件等。这里就不一一列举了,可阅读 MDN 文档获得更多信息。</p>
<p><strong>MDN 事件文档:</strong></p>
<p>https://developer.mozilla.org/zh-CN/docs/Web/Events<br>
https://developer.mozilla.org/zh-CN/docs/Web/API/Element/copy_event</p>
<h2 id="事件绑定">事件绑定</h2>
<p>见过常用事件之后,再聊聊 JS 绑定事件的几种方式,以 <code>click</code> 事件为例。</p>
<p>最开始学习 JS 的时候,就用的是 HTML 标签属性的方式绑定事件,比如这样:</p>
<pre><code class="language-html">&lt;!-- 所有的 HTML 事件属性都以 on 开头,比如 onclick onload onkeydown --&gt;
&lt;button onclick="handleClick()"&gt;这里是按钮&lt;/button&gt;
&lt;script&gt;
function handleClick() {
    alert('点击了按钮')
}
&lt;/script&gt;
</code></pre>
<p>慢慢的学习之后发现这种方式有个弊端啊,handleClick 这个函数名定义在全局作用域之下,这东东可被称为 <code>污染全局变量</code> 了,后来就用上了这种方式:</p>
<pre><code class="language-html">&lt;button id="button"&gt;这里是按钮&lt;/button&gt;
&lt;script&gt;
(() =&gt; {
// 所有的事件属性都以 on 开头,比如 onclick onload onkeydown
document.querySelector('#button').onclick = () =&gt; {
    alert('前端路引点击了按钮')
}
})()
&lt;/script&gt;
</code></pre>
<p>这种方式虽然看起来没啥大问题,但是如果一个 DOM 节点绑定了两个相同的事件之后,只会执行最后一个绑定的方法,比如:</p>
<pre><code class="language-html">&lt;button id="button2"&gt;这里是按钮&lt;/button&gt;
&lt;script&gt;
(() =&gt; {
const btn = document.querySelector('#button2')
btn.onclick = () =&gt; {
    alert('点击了按钮')
}
btn.onclick = () =&gt; {
    alert('前端路引点击了按钮')
}
})()
&lt;/script&gt;
</code></pre>
<p>还是存在弊端,如果团队合作的时候,有其他兄弟伙用这种方式绑定就完蛋了,所以后来又学到了一种新的方式:</p>
<pre><code class="language-html">&lt;button id="button3"&gt;这里是按钮&lt;/button&gt;
&lt;script&gt;
(() =&gt; {
const btn = document.querySelector('#button3')
// addEventListener 绑定的事件不需要添加 on 前缀
btn.addEventListener('click', () =&gt; {
    alert('点击了按钮')
})
btn.addEventListener('click', () =&gt; {
    alert('前端路引点击了按钮')
})
})()
&lt;/script&gt;
</code></pre>
<p>嗯,这种绑定方式就<strong>完美</strong>了,在任何地方都可以绑定,还能一个事件多次绑定,也不存在全局污染。</p>
<h2 id="取消绑定">取消绑定</h2>
<p>有绑定事件,那必然就有取消绑定的需求。某些场景下,绑定的事件只需要执行一次,这种需求其实用一个变量也能实现,比如:</p>
<pre><code class="language-html">&lt;button id="button4"&gt;这里是按钮&lt;/button&gt;
&lt;script&gt;
(() =&gt; {
const btn = document.querySelector('#button4')
let isClicked = false
btn.addEventListener('click', () =&gt; {
    if (isClicked) {
      return
    }
    isClicked = true
    alert('前端路引点击了按钮')
})
})()
&lt;/script&gt;
</code></pre>
<p>再复杂一点,搞一个计数器,想限制多少次就限制多少,比如限制按钮只能点击五次:</p>
<pre><code class="language-html">&lt;button id="button5"&gt;这里是按钮&lt;/button&gt;
&lt;script&gt;
(() =&gt; {
const btn = document.querySelector('#button5')
let times = 0
btn.addEventListener('click', () =&gt; {
    if (times &gt;= 5) {
      return
    }
    times++
    alert('前端路引点击了按钮' + times)
})
})()
&lt;/script&gt;
</code></pre>
<p>虽然这种方式也能满足需求,但与取消绑定的方式多少有点出入,还是聊聊取消绑定的几种方法。</p>
<p>使用 HTML 标签属性绑定的事件,可通过 <code>removeAttribute</code> 方法取消绑定:</p>
<pre><code class="language-html">&lt;button onclick="handleClick(this)"&gt;这里是按钮&lt;/button&gt;
&lt;script&gt;
function handleClick(el) {
    alert('点击了按钮')
    el.removeAttribute('onclick')
}
&lt;/script&gt;
</code></pre>
<p>使用 <code>onclick</code> 绑定的事件,可通过将属性置空取消绑定:</p>
<pre><code class="language-html">&lt;button id="button2"&gt;这里是按钮&lt;/button&gt;
&lt;script&gt;
(() =&gt; {
const btn = document.querySelector('#button2')
btn.onclick = () =&gt; {
    btn.onclick = undefined
    alert('点击了按钮')
}
})()
&lt;/script&gt;
</code></pre>
<p>使用 <code>addEventListener</code> 绑定的事件,可通过 <code>removeEventListener</code> 方法取消绑定:</p>
<pre><code class="language-html">&lt;button id="button3"&gt;这里是按钮&lt;/button&gt;
&lt;script&gt;
(() =&gt; {
const btn = document.querySelector('#button3')
function handleClick() {
    alert('前端路引点击了按钮')
    // 点击后移除事件
    btn.removeEventListener('click', handleClick)
}
btn.addEventListener('click', handleClick)
})()
&lt;/script&gt;
</code></pre>
<p>removeEventListener 第二个参数必须传入要移除的事件函数,否则方法报错!!</p>
<p>关于<strong>只执行一次</strong>的事件,也可以用 <code>addEventListener</code> 的第三个参数 <code>once</code> 来处理,比如:</p>
<pre><code class="language-html">&lt;button id="button4"&gt;这里是按钮&lt;/button&gt;
&lt;script&gt;
(() =&gt; {
const btn = document.querySelector('#button4')
btn.addEventListener('click', () =&gt; {
    alert('前端路引点击了按钮')
}, { once: true })
})()
&lt;/script&gt;
</code></pre>
<h3 id="abortcontroller-移除事件">AbortController 移除事件</h3>
<p>曾一度以为 <code>AbortController</code> 这个 API 仅用于终止 <code>fetch</code> 请求,后来发现也可以用于移除 DOM 事件,比如:</p>
<pre><code class="language-html">&lt;button id="button5"&gt;这里是按钮&lt;/button&gt;
&lt;script&gt;
(() =&gt; {
const btn = document.querySelector('#button5')

const controller = new AbortController();

btn.addEventListener('click', () =&gt; {
    alert('点击了按钮')
}, { signal: controller.signal })

btn.addEventListener('click', () =&gt; {
    alert('前端路引点击了按钮')
    // 移除所有通过此 signal 绑定的事件
    controller.abort();
}, { signal: controller.signal })
})()
&lt;/script&gt;
</code></pre>
<p>这个 API 的强大之处在于可一次性移除多个事件,嗯..比 <code>removeEventListener</code> 是要更加方便。</p>
<h2 id="写在最后">写在最后</h2>
<p>虽然 Vue / React 中的 <code>DOM 事件</code> 框架已经整合优化,但某些需求场景还是免不了要使用原生的 DOM 事件,某个 Vue 组件元素要随窗口滚动而发生变化,这时候还是得靠原生的事件来实现。</p>


</div>
<div id="MySignature" role="contentinfo">
    <p>&nbsp;</p>
<p style="font-size: 18px;font-weight: bold;">文章首发于微信公众号【<span style="color:rgb(255, 71, 87)">前端路引</span>】,欢迎 <span style="color:#4ec259">微信扫一扫</span> 查看更多文章。</p>
<p>
<img style="max-width: 320px;" src="https://images.cnblogs.com/cnblogs_com/linx/2447020/o_250228035031_%E5%85%AC%E4%BC%97%E5%8F%B7%E4%BA%8C%E7%BB%B4%E7%A0%81.png"/>
</p>
<p>本文来自博客园,作者:前端路引,转载请注明原文链接:https://www.cnblogs.com/linx/p/18957244</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/linx/p/18957244
頁: [1]
查看完整版本: Web前端入门第 73 问:JavaScript DOM 常用事件那点小事