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

为何父元素调用e.preventDefault()会阻止默认事件?且e.defaultPrevented为false?

问题:点击导航链接时默认行为被阻止,但子元素事件中e.defaultPrevented却返回false?

点击.nav__link元素的默认行为是跳转到页面对应区块:

  • 父元素.nav__links未添加e.preventDefault()时,默认行为正常执行;
  • 给父元素添加e.preventDefault()后,默认行为被阻止,但子元素事件处理函数里console.log(e.defaultPrevented)输出false,原本预期默认行为仍会执行,这是为什么?

示例代码

// 子元素事件监听 ------------------------
document.querySelectorAll('.nav__link').forEach(function (val, i) {
  val.addEventListener('click', function (e) {
    const id = this.getAttribute('href');
    document.querySelector(id).scrollIntoView({ behavior: 'smooth' });
    console.log(e.defaultPrevented); // 输出 false
  });
});

// 父元素事件监听 -------------------------------
document.querySelector('.nav__links').addEventListener('click', function (e) {
  console.log('parent');
  e.preventDefault();
});

原因解析

核心问题出在事件执行顺序和**defaultPrevented的更新时机**上:

  1. 事件冒泡的执行顺序:你给子元素和父元素绑定的都是冒泡阶段的事件监听(addEventListener默认就是冒泡阶段触发),所以点击.nav__link时,会先执行子元素的点击回调,再执行父元素的点击回调。
  2. defaultPrevented的时效性:子元素回调里的console.log(e.defaultPrevented)执行时,父元素的e.preventDefault()还没运行——这个属性只记录到当前代码执行时刻为止,有没有调用过preventDefault(),所以此时输出false是正常的。
  3. 默认行为的触发时机:浏览器的默认行为(比如链接跳转)是在所有冒泡和捕获阶段的事件处理函数都执行完毕之后才会触发的。父元素的回调在子元素之后执行,调用e.preventDefault()后,会标记这个事件的默认行为要被阻止,所以最后原本的跳转行为就被取消了。

简单说就是:子元素的代码先跑,这时候还没人阻止默认行为,所以defaultPrevented是false;等父元素的代码跑了才阻止,但这时候子元素的console.log已经输出完了,而默认行为要等所有事件处理完才执行,所以最终还是被阻止了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 11:36:04