web-dev-qa-db-ja.com

いずれかの子がフォーカスを受け取った場合にblurイベントを発生させない

特定のカテゴリ(画像、名前など)に関する情報を表示するdivがページにあります。

編集画像をクリックすると、カテゴリが編集モードになり、名前を更新できます。下の画像を見るとわかるように、「スープ」は現在編集モードにあり、その他は通常の表示モードになっています。これはすべて、キャンセル/保存ボタンがすべて正しく機能することで期待どおりに機能します。 (私は画像を追加しようとしましたが、私を許しませんでした、もっと愛が必要です)

ただし編集モードで1回(divの外で)ページの他の場所をクリックすると、期待どおりの結果として、スープカテゴリが表示モードに戻ります。なんらかのイベントが発生すると、変更を保存するかどうかを尋ねることもできます。

そこで、私が決定したのは、「スープ」親divにblurイベントを作成することです。これは、ページの任意の場所をクリックすると予想どおりに機能しますが、divの内部要素をクリックすると、親のblurイベントが発生し、カテゴリが表示モードに戻ります。

それで、その子のいずれかがフォーカスを受け取った場合に親divがblurイベントを発生させないようにする方法はありますか?

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

私はコンパイラーなしでコードを書いただけなので、それがうまくいくかどうかはわかりませんが、うまくいけばあなたはアイデアを得るでしょう。

私はKnockout.jsを使用してGUIをオンザフライで更新していますが、これは私が考えていなかったこの答えには影響しないはずです。

26
Thwaitesy

以前にこの問題に取り組む必要がありました。それが最善の解決策であるかどうかはわかりませんが、私が最終的に使用したものです。

ぼかしの後にクリックイベントが発生するので、どの要素がフォーカスを得ているかを(ブラウザ間で信頼できる)確認する方法はありません。

ただし、マウスダウンはぼかしの前に発生します。これは、子要素のマウスダウンにフラグを設定し、親のブラーでそのフラグを問い合わせることができることを意味します。

作業例: http://jsfiddle.net/L5Cts/

キーボードによるぼかしもキャッチしたい場合は、keydownを処理する必要があります(そしてタブ/シフトタブを確認する必要があります)。

34
jbabey

すべてのブラウザーでフォーカスイベントの前にmousedownが発生するという保証はないと思います。そのため、これを処理するためのより良い方法は evt.relatedTargetfocusinイベントの場合、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
    }
});
10
Rob Allsopp