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

推荐订阅源

月光博客
月光博客
Stack Overflow Blog
Stack Overflow Blog
L
LangChain Blog
Jina AI
Jina AI
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
雷峰网
雷峰网
T
Tailwind CSS Blog
MongoDB | Blog
MongoDB | Blog
博客园 - 【当耐特】
博客园 - 聂微东
V
Visual Studio Blog
博客园_首页
Engineering at Meta
Engineering at Meta
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
The Cloudflare Blog
人人都是产品经理
人人都是产品经理
Apple Machine Learning Research
Apple Machine Learning Research
阮一峰的网络日志
阮一峰的网络日志
Microsoft Security Blog
Microsoft Security Blog
GbyAI
GbyAI
F
Fortinet All Blogs
C
Check Point Blog
罗磊的独立博客
H
Hackread – Cybersecurity News, Data Breaches, AI and More

博客园 - 前端路引

高精度计算插件 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 这组事件使用率相对而言较高一些。