【问题标题】:Prevent firing the blur event if any one of its children receives focus如果任何一个孩子获得焦点,则防止触发模糊事件
【发布时间】:2012-08-19 00:08:59
【问题描述】:

我在页面上有一个 div,显示有关特定类别(图像、名称等)的一些信息。

当我单击编辑图像时,它会将类别置于编辑模式,允许我更新名称。从下图中可以看出,“Soup”当前处于编辑模式,其他处于正常视图模式。这一切都按预期工作,取消/保存按钮一切正常。 (我尝试添加图片但不让我,需要更多的爱)

但是一旦进入编辑模式,如果我单击页面上的其他任何位置(div 之外),预期结果将是汤类别将返回查看模式。在某种事件触发时,这也应该允许我询问他们是否要保存更改。

然后我决定做的是在“汤”父 div 上创建一个模糊事件。如果我单击页面上的任何位置,这将按预期工作,但是如果我单击 div 的内部元素,它也会导致父母模糊事件被触发,从而导致类别返回查看模式。

那么,如果父 div 的任何一个子元素获得焦点,有没有办法阻止父 div 触发 blur 事件?

<div tabindex="-1" onblur="alert('outer')">
    <input type="text" value="Soup" />
</div>

我只是在没有编译器的情况下编写了代码,所以不确定这是否可行,但希望你能明白这一点。

我正在使用 Knockout.js 即时更新 GUI,但这不会影响我没想到的答案。

【问题讨论】:

标签: javascript jquery knockout.js onblur


【解决方案1】:

我遇到了同样的问题。这对我有用。

 handleBlur(event) {
    // if the blur was because of outside focus
    // currentTarget is the parent element, relatedTarget is the clicked element
    if (!event.currentTarget.contains(event.relatedTarget)) {
        .....
    }
}

享受:)

【讨论】:

  • 经过一些编辑,我得到了这个做我想做的事;必须处理relatedTarget === null 的情况。似乎仍然比使用 mousedown 更合适。
  • 这对我也有用,谢谢你的帮助
  • 这是迄今为止最好的答案。
  • 如果您在使用 Typescript (Argument of type 'EventTarget' is not assignable to parameter of type 'Node'.) 时遇到打字问题,您可以写成 currentTarget.contains(e.relatedTarget as Node)
  • 有人可以添加完整代码以供参考@yahel,@petermoore
【解决方案2】:

我以前必须解决这个问题。我不确定这是否是最好的解决方案,但这是我最终使用的。

由于点击事件在模糊之后触发,因此没有(跨浏览器,可靠的)方法来判断哪个元素正在获得焦点。

然而,Mousedown 在模糊之前触发。这意味着您可以在子元素的 mousedown 中设置一些标志,并在父元素的模糊中询问该标志。

工作示例:http://jsfiddle.net/L5Cts/

请注意,如果您还想捕捉由键盘引起的模糊,还必须处理 keydown(并检查 tab/shift-tab)。

【讨论】:

  • 先生,您是一位绅士和一位学者。一年多来,我一直在不同情况下尝试不同的解决方案来解决这个问题。从来没有意识到所有事件的时间,谢谢一百万。
  • 我一直在尝试找到某种事件顺序/优先级的官方定义,看看是否可以依赖它。这是一个老问题,但如果答案仍然正确,这个解决方案可能只是因为巧合:stackoverflow.com/a/282271/2382483。我很想找到一个真正可靠的解决方案,但一切似乎都是一种变通或破解。
  • 这个例子虽然适用于 React,但可以很好地适应任何用途。它在新元素上使用焦点并在原始元素上使用模糊,并使用计时器在焦点触发时取消模糊事件。 medium.com/@jessebeach/…
  • 这可能是一个 hack,但我在模糊上使用 setTimeout,在子点击上使用 clearTimeout。
【解决方案3】:

我认为没有任何保证mousedown 会在所有浏览器的焦点事件之前发生,因此更好的处理方法可能是使用evt.relatedTarget。对于focusin 事件,eventTarget 属性是对当前失去焦点的元素的引用。您可以检查该元素是否是父元素的后代,如果不是,则您知道焦点从外部进入父元素。对于focusout 事件,relatedTarget 是对当前接收焦点的元素的引用。使用相同的逻辑来确定焦点是否完全离开父项:

const parent = document.getElementById('parent');

parent.addEventListener('focusin', e => {
    const enteringParent = !parent.contains(e.relatedTarget);

    if (enteringParent) {
        // do things in response to focus on any child of the parent or the parent itself
    }
});

parent.addEventListener('focusout', e => {
    const leavingParent = !parent.contains(e.relatedTarget);

    if (leavingParent) {
        // do things in response to fully leaving the parent element and all of its children
    }
});

【讨论】:

  • react 不允许使用 focusin 或 focusout :/
  • 太糟糕了,至少 vuejs 可以
  • @WouldBeNerd React 中的合成 onBlur / onFocus 事件会冒泡(就像它们的原生表亲 focusout / fousin),因此你可以在 React 中使用它们:&lt;div onBlur={event =&gt; { if (!event.currentTarget.contains(event.relatedTarget)) doStuff(); }} /&gt; 顺便说一句,你可以 在 React 中使用原生事件;你只需要得到一个ref 并调用addEventListener(可以包裹在hook 中)
猜你喜欢
  • 1970-01-01
  • 2013-05-12
  • 1970-01-01
  • 2013-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多