惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
爱范儿
爱范儿
H
Help Net Security
V
Visual Studio Blog
J
Java Code Geeks
Stack Overflow Blog
Stack Overflow Blog
Microsoft Security Blog
Microsoft Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
MyScale Blog
MyScale Blog
The Cloudflare Blog
Martin Fowler
Martin Fowler
D
Docker
腾讯CDC
F
Fortinet All Blogs
雷峰网
雷峰网
GbyAI
GbyAI
G
Google Developers Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Blog — PlanetScale
Blog — PlanetScale
Engineering at Meta
Engineering at Meta
博客园 - 聂微东
博客园 - 叶小钗

博客园 - 前端路引

高精度计算插件 decimal.js 处理 JS 浮点数精度问题(0.1 + 0.2 !== 0.3) 还在痛苦前端的拖拽排序吗?SortableJS 轻松搞定 浏览器 15 个常见指纹特征,使用插件 FingerprintJS 生成浏览器指纹 Web前端入门第 90 问:JavaScript 也能无中生有的创建音频 Web前端入门第 89 问:总结 8 种跨域通信处理方案 Web前端入门第 88 问:引入 JavaScript 的 script 标签究竟有多少用法? Web前端入门第 87 问:JavaScript 中 setInterval 和 setTimeout 细节 Web前端入门第 86 问:JavaScript 中的 Web Worker 为什么能提升代码性能? Web前端入门第 85 问:JavaScript 一个简单的 IndexedDB 数据库入门示例 Web前端入门第 84 问:JavaScript sessionStorage 那些容易踩坑的地方 Web前端入门第 83 问:JavaScript localStorage 有大小限制吗?溢出会怎样? Web前端入门第 82 问:JavaScript cookie 有大小限制吗?溢出会怎样? Web前端入门第 81 问:JavaScript cookie 的读写操作 Web前端入门第 80 问:JavaScript 哪些地方需要 try...catch 异常捕获 Web前端入门第 79 问:JavaScript async & await 的异步任务进化之路 Web前端入门第 78 问:JavaScript 比较少见的模版字符串用法 Web前端入门第 77 问:JavaScript 由程序触发绑定事件的几种方式 Web前端入门第 75 问:JavaScript 性能优化之事件委托(事件代理)原理 Web前端入门第 74 问:JavaScript 事件冒泡与事件捕获
Web前端入门第 76 问:JavaScript 鼠标事件(mouse) enter/lea...
前端路引 · 2025-07-08 · via 博客园 - 前端路引

题外话

在考察事件基础的时候,会经常被问及 clickmousedownmouseup 它们三者执行的先后顺序是怎样的?

如果平时没太注意,这细节可能就会忽略,毕竟很少会在同一个元素上面同时绑定这三个事件~~

直接上示例:

<div class="c">测试点击事件</div>

<script>
  (() => {
    const c = document.querySelector('.c')
    c.addEventListener('click', () => {
      console.log('click')
    })
    c.addEventListener('mousedown', () => {
      console.log('mousedown')
    })
    c.addEventListener('mouseup', () => {
      console.log('mouseup')
    })
  })()
</script>

实际控制台输出:

76-1

而且 click 事件鼠标在元素上点击之后,再按住鼠标移开元素,此时并不会触发 click 事件,仅 mousedown 事件被触发了。
这里就有一个比较有意思的操作了,如果开发中想要用户无法取消事件,那就直接用 mousedown 事件吧~~

事件 enter/leave 和 over/out 区别

这两组事件都是鼠标进入元素和离开元素时触发,用文字描述的区别就是 over/out 这一组事件会冒泡,而 enter/leave 这组事件不会冒泡。

如果绑定事件没有子元素,其实两者没有任何区别,比如:

<style>
  .c {
    border: 1px solid #000;
    padding: 8px;
  }
</style>

<div class="c">前端路引--事件测试</div>

<script>
  (() => {
    const c = document.querySelector('.c')
    c.addEventListener('mouseover', () => {
      console.log('mouseover')
    })
    c.addEventListener('mouseout', () => {
      console.log('mouseout')
    })
    c.addEventListener('mouseenter', () => {
      console.log('mouseenter')
    })
    c.addEventListener('mouseleave', () => {
      console.log('mouseleave')
    })
  })()
</script>

效果:

76-2

可以明显看到,这两组事件触发都是一样的,在鼠标移入和移除的时候都触发了。

但这里有一个细节:enter/leave 这组事件永远都是在 over/out 后面触发,不论代码的先后顺序,也不论是否是事件捕获!!

存在子元素时

上面事件看不出区别来,别急,来一个包含子元素的例子:

<style>
  .bd {
    border: 1px solid #000;
    padding: 8px;
  }
</style>

<div id="container1" class="bd">
  外层
  <div class="bd">
    内层
    <div class="bd">
      最内层
      <div class="bd">
        按钮
      </div>
    </div>
  </div>
</div>

<script>
  (() => {
    const c = document.querySelector('#container1')
    c.addEventListener('mouseover', () => {
      console.log('mouseover')
    })
    c.addEventListener('mouseout', () => {
      console.log('mouseout')
    })
    c.addEventListener('mouseenter', () => {
      console.log('mouseenter')
    })
    c.addEventListener('mouseleave', () => {
      console.log('mouseleave')
    })
  })()
</script>

效果:

76-3

可以看到 over/out 这组事件,在鼠标每次进入子元素时候,都会触发父元素的 over/out 事件;而 enter/leave 这组事件只会在进入/离开父元素时候触发一次。

前面说了,over/out 是冒泡事件,那能不能通过 event.stopPropagation() 来阻止冒泡?

把所有事件都添加上 阻止传播 试试:

(() => {
  const c = document.querySelector('#container1')
  c.addEventListener('mouseover', (event) => {
    event.stopPropagation()
    console.log('mouseover')
  })
  c.addEventListener('mouseout', (event) => {
    event.stopPropagation()
    console.log('mouseout')
  })
  c.addEventListener('mouseenter', (event) => {
    event.stopPropagation()
    console.log('mouseenter')
  })
  c.addEventListener('mouseleave', (event) => {
    event.stopPropagation()
    console.log('mouseleave')
  })
  document.querySelectorAll('.bd').forEach((item) => {
    item.addEventListener('mouseover', (event) => {
      event.stopPropagation()
    })
    item.addEventListener('mouseout', (event) => {
      event.stopPropagation()
    })
  })
})()

效果:

76-4

可以看到虽然 最内层 里面的元素移动不会触发顶层事件,但在 内层外层 来回移动的时候,还是会触发事件冒泡。

可以理解为每个子元素都有物理空间,over/out 这组事件在父元素和子元素的物理空间来回移动的时候,还是会触发 over/out 事件。

写在最后

开发中需要根据需求选择合适的事件,一般情况 enter/leave 这组事件使用率相对而言较高一些。