typescript 实现单击外部时出现意外行为

chy5wohz  于 2023-06-24  发布在  TypeScript
关注(0)|答案(1)|浏览(128)

我正在实现一个简单的click-outside特性,它使用一个编辑字段关闭组件。为此,我在根元素中添加了一个click事件侦听器,并尝试查看被单击的元素(事件目标)是否是它的后代。问题是,单击的事件目标恰好是切换组件以显示的按钮。因此,组件出现并立即消失。
Vue Playground(参见添加的控制台日志)
怎么会这样?添加单击事件侦听器的组件应该在单击按钮并装载组件之后执行此操作。
setTimeout修复了这个问题,但我仍然无法理解为什么它会这样工作。

e4yzc0pl

e4yzc0pl1#

我不是vuejsMaven,所以我不能肯定vue生命周期的哪一部分是同步发生的。看起来确实像是在冒泡事件到达文档根之前执行了mount(由按钮单击触发)。
我可以想到几个潜在的修复方法:
1.在TitleEdit组件中移动按钮,这是它在初始状态下唯一可见的元素。按钮将不再位于this.$refs.container元素的外部,问题得到了优雅的解决。
1.在click事件上调用stopPropagation。我强烈反对这样做。因为一旦UI的其他部分依赖于到达文档根的冒泡事件,这将导致错误行为。也就是说,只要你在同一个视图中第二次使用button和TitleEdit组件的组合。(我在blog article中介绍了这个主题)
1.在click事件中引入一个自定义标志,以通知根事件处理程序忽略此特定事件:

@click="editing = true; $event.titleEditIgnore = true;"
cancelOnClickOutside (event: MouseEvent): void {
   if (event.titleEditIgnore === true)
     return;

   const clickedInside = this.$refs.container.contains(event.target)
   console.log('event target: ', event.target)
   !clickedInside && this.cancel()
 }

但是这个解决方案是有缺陷的,因为一旦你使用了第二对按钮和编辑组件,任何一个编辑按钮都不会被算作对任何一个编辑组件的外部点击。
(The我在这里不使用defaultPrevented的原因是因为它用于表示事件已经被处理(例如:一个点击的<a>)到事件处理程序,只对未处理的事件起作用。这不是你的外部点击检测器的情况)。
1.在capture阶段让外部点击检测器监听;因此它将错过按钮点击的捕获阶段并忽略冒泡点击。

mounted (): void {
   console.log('registered event handler')
   document.addEventListener('click', this.cancelOnClickOutside, { capture: true })
 },
 unmounted (): void {
   console.log('removed event handler')
   document.removeEventListener('click', this.cancelOnClickOutside, { capture: true })
 },

这可能会解决问题,但我不认为这是一个非常明确的解决方案。它可能会让其他维护人员感到困惑。
如果我必须选择,我会选择解决方案#1,如果不可能,我会选择解决方案#4。

相关问题