You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firefox中mousedown异步等待后offsetX/offsetY变为0的原因

跨浏览器事件offsetX属性差异问题

问题复现代码

JavaScript 代码

const $test = document.querySelector('.test');

function sleep() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve();
    }, 300);
  });
}
$test.addEventListener('mousedown', async e => {
  console.log(e.offsetX, e.offsetY); // 正常场景下为非0值,例如(90, 163)
  await sleep();
  console.log(e.offsetX, e.offsetY); // Firefox环境下返回0 0
});

CSS 样式

#app {
  position: relative;
  width: 100vw;
  height: 100vh;
}

.test {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 300px;
  height: 300px;
  background-color: aqua;
}

HTML 结构

<div id="app">
  <div class="test"></div>
  <!-- <canvas width="300" height="300" class="test"></canvas> -->
</div>

异常表现

上述代码在Chrome浏览器中运行正常,在Firefox浏览器中存在异常:

  • 执行sleep异步等待前,读取mousedown事件对象e的offsetX、offsetY属性为正常非0值;
  • 经过300ms的await等待后,再次读取e.offsetX、e.offsetY的值变为0。

差异产生原因

这个跨浏览器表现差异,根源是两个浏览器对DOM事件对象属性的存储、计算策略不同:

  • 先明确基础规则:offsetX/offsetY属于计算属性,作用是返回鼠标指针相对于事件目标元素内边距边界的偏移值,本身不是事件触发时就写死在对象上的固定值。
  • Chrome的实现逻辑:mousedown这类用户交互事件进入同步派发流程时,会第一时间计算offsetX/offsetY的结果,把值缓存到事件对象上。哪怕后续用await跳出了原生事件的同步调用栈,异步阶段读取属性时拿到的还是之前缓存的固定值,不会出现变0的问题。
  • Firefox的实现逻辑:Firefox不会主动缓存这两个计算属性的值,只有当代码还处在事件原生同步派发的调用栈里时,读取属性才会实时拉取鼠标坐标、元素边界等数据计算返回正确结果。一旦await让出执行线程,代码脱离了最初的事件同步上下文,事件关联的原生临时数据(包括触发瞬间的鼠标位置、目标元素尺寸位置等计算必需的原始参数)就会被回收,此时再读取offsetX/offsetY拿不到计算依据,就会直接返回默认值0。

这个问题的规避方式非常简单:如果要在异步逻辑里用到这两个坐标值,在await执行前就把e.offsetX、e.offsetY的值赋值给普通变量保存,后续用变量里存的值即可,这种写法在两个浏览器下表现完全一致。

内容的提问来源于stack exchange,提问作者panda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 23:09:31