已经有一些尝试来回答这个问题:
hereherehere 。然而,没有一个答案给出了可靠的回应。我不是指 event 阶段 capturebubbletarget 以及 stopPropagation() 如何影响整个事件。我正在寻找将 stopPropagation() 添加到 DOM 节点将有利于整体代码的情况?

最佳答案

这真的不应该是一个答案,但你只能在一个评论中写这么多

我认为您在标题中使用“良好实践”一词并没有公正地对待您的问题。这种暗示在大多数情况下,stopPropagation 是不好的做法。这类似于说 eval 是邪恶的。它以错误的教条主义完全抹杀了它的任何合法用例。

我从来没有发现自己处于使用 stopPropagation 感觉不像是避免解决真正问题的解决方法的情况。

在理想的世界中,应用程序由较小的组件构建而成,这些组件本身几乎没有什么作用,但具有高度的可重用性和可组合性。为此,秘诀很简单,但执行起来却非常困难:每个组件必须对外部世界一无所知。

因此,如果一个组件需要使用 stopPropagation() ,那只能是因为它知道链上的某些东西会中断,或者它会使您的应用程序进入不良状态。

在这种情况下,您应该问自己这是否不是设计问题的症状。也许您需要一个组件来编排和管理其子项的事件?

您还应该考虑这样一个事实,即阻止事件传播可能会导致其他组件行为不端。典型的例子是一个下拉菜单,当你点击它的外部时它就会关闭。如果该点击停止,您的下拉菜单可能永远不会关闭。

将事件视为数据源。您不想丢失数据。反之!让它去,让它自由;)

虽然我不认为使用 stopPropagation 是不好或邪恶的做法,但我认为它永远不需要。

示例:如何避免使用 stopPropagation

在这个例子中,我们正在构建一个非常简单的游戏:如果你点击红色区域你输了,点击绿色区域你赢了。点击一次游戏就结束了。

const onClick = (selector, handler) => {
  document.querySelector(selector).addEventListener('click', handler);
};

onClick('#game', () => console.log('game over'));
onClick('#red', () => console.log('you lost'));
onClick('#green', () => console.log('you won'));
#red, #green { width: 50px; height: 50px; display: inline-block; }
#red { background-color: orangered; }
#green { background-color: yellowgreen; }
<div id="game">
  <div id="red"></div>
  <div id="green"></div>
</div>


现在让我们想象一下,有不同级别的红色和绿色块随机排列。在第 42 关中,红色方块包含绿色方块。

const onClick = (selector, handler) => {
  document.querySelector(selector).addEventListener('click', handler);
};

onClick('#game', () => console.log('game over'));
onClick('#red', () => console.log('you lost'));
onClick('#green', () => console.log('you won'));
#red, #green { max-width: 100px; padding: 10px; }
#red { background-color: orangered; }
#green { background-color: yellowgreen; }
<div id="game">
  <div id="red">
    <div id="green"></div>
  </div>
</div>


正如您在点击绿色区域时所看到的,您同时输赢!如果您要在绿色处理程序中调用 stopPropagation() 调用,则将无法赢得这场比赛,因为点击不会冒泡到游戏处理程序以发出游戏结束的信号!

解决方案一:确定点击来源

const filter = handler => ev =>
  ev.target === ev.currentTarget ? handler(ev) : null;

const onClick = (selector, handler) => {
  document.querySelector(selector).addEventListener('click', handler);
};

onClick('#game', () => console.log('game over'));
onClick('#red', filter(() => console.log('you lost')));
onClick('#green', () => console.log('you won'));
#red, #green { max-width: 100px; padding: 10px; }
#red { background-color: orangered; }
#green { background-color: yellowgreen; }
<div id="game">
  <div id="red">
    <div id="green"></div>
  </div>
</div>


关键函数是 filter 。它将确保 handler 仅在点击实际上来自节点本身而不是来自其子节点之一时才会执行。



https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget

方案二:使用事件委托(delegate)

您实际上并不需要三个事件处理程序。只需在 #game 节点上设置一个。

const onClick = (selector, handler) => {
  document.querySelector(selector).addEventListener('click', handler);
};

onClick('#game', (ev) => {
  if (ev.target.id === 'red') {
    console.log('you lost');
  } else if (ev.target.id === 'green') {
    console.log('you won');
  }
  console.log('game over');
});
#red, #green { max-width: 100px; padding: 10px; }
#red { background-color: orangered; }
#green { background-color: yellowgreen; }
<div id="game">
  <div id="red">
    <div id="green"></div>
  </div>
</div>

关于javascript - 什么时候使用 stopPropagation() 的好习惯?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54815439/

10-12 17:57