1

HTMLに次の構造があり、コンテンツdiv内のいくつかの要素にさまざまなキー(押す、上、下)イベントがあるとします。

<html>
<head></head>
<body>
    <div id="content">All the content</div>
</body>
</html>

jQueryによって絶対位置のdivを追加します。

$('body').append('<div id="lightbox">etc.</div>');

一時的に(ライトボックスが存在する間)、すべてのキーボードイベントがキャッチされたり、その子だけ にバブリングされたりしないようにするにはどうすればよいですか$('#content')。これにより、上記の構造のライトボックスが存在する場合のバブリング順序は次のようになります。

  1. $('#lightbox *')
  2. $('#lightbox')
  3. $('body')
  4. $('html')

一方、

  1. $('#content *')
  2. $('#content')
  3. $('body')
  4. $('html')

ライトボックスがなくなったとき?

編集:ここにいくつかの追加情報があります。

  • すべてのフォーム要素を無効または読み取り専用にすることはできません(これはとにかく限られた要素に適用されます)。ライトボックスは、一意のキーイベントをすでに割り当てている多くのフォーム要素の上に存在する場合があるためです。

  • また、キーイベントがウィンドウ+(ライトボックスがある場合はそれ以外の場合はコンテンツ)に影響を与えるようにしたいので、すべてのイベントの伝播を直接停止することはできません

  • 上記の順序は、1-4ではなく4-1にすることができますが、問題ではありません。重要なのは、重要なイベントでこの特定の要素のコンテンツ(ライトボックスまたは状況に応じたコンテンツ)をバイパスすることです。

4

3 に答える 3

1

私が正しく理解していれば、ライトボックスが表示されているときに重要なイベントを選択的に禁止する必要があります。

これを行う最も簡単な方法は、次のように、イベントハンドラー内に抑制を配置することだと思います。

  • ライトボックスがアクティブ/非アクティブのときにフラグを上げたり下げたりします
  • 禁止したいイベントのすべてのハンドラー内で、フラグが立てられたらすぐに戻ります。

(フラグを使用せずに、ライトボックスの状態を直接テストできる場合があります)

このアプローチは、大まかに言って次のいずれかを含む代替案よりもはるかに簡単なはずだと思います。

  • イベント伝播の防止/許可
  • ハンドラーの切り離しと再接続。

編集

インハン、あなた自身の解決策を読んだ後、これが物事を単純に保つことについての私の考えです。

タビング

ライトボックスダイアログが開いているときにタブオーダーをエミュレートするよりも、タブオーダーを制御するためのより簡単なアプローチが必要です。

達成する必要のある効果のすべてが、現在開いているダイアログにない(そしてjQuery UIライトボックスを想定している)要素を形成するためのタブの抑制である場合は、単にmodal: trueオプションを設定します。その他のライトボックスプラグインについては、それらのドキュメントを参照してください。

バブリング

HTMLを適切に構成することで、ライトボックスから「ドキュメント」またはその他のコンテナへの不要なイベントのバブリングを排除できるはずです。次のルールに従ってください:

  • イベントをに委任しないでくださいdocument。より多くのローカルコンテナを選択します。<div id="pseudoBody">...</div>必要に応じて、イベント委任の明確な目的のために、ライトボックス以外のすべてをでラップします。の代わりに、この専用のスタイルなしラッパーにイベントを委任しますdocument
  • ライトボックスが、イベントが委任されているコンテナ内にネストされていないことを確認してください。採用された場合、ライトボックスを1レベル以内に配置し<body>、確実に外側に配置pseudoBodyします。
  • 一部のライトボックスイベントのバブルを許可する必要がある場合は、ライトボックスコンテナに委任します。コードを節約するために(そして適切な場合)、または他の場所にアタッチされているのと同じ(名前付き)イベントハンドラーをアタッチできpseudoBodyます。
于 2012-09-14T03:26:05.030 に答える
0

信頼できる解決策が見つからなかったので、独自の関数を作成することにしました。私はそれをいじるのはあまり幸せではありませんが、TABキーの動作を制御し、グローバルなキーアップ/キーダウン関数を作成する必要がありました。

興味のある人のために、私はSOでいくつかのリソースを見つけました、ここここ、そしてここ

スクリプトのアンカーに「disabled」という名前のCSSクラスを割り当てていることに注意してください。これにより、コードに表示されるdisabled="disabled"ものを、該当する要素の属性のように考慮することができます。また、HTMLコンテンツからブラウザの選択可能なUI要素に焦点を合わせる方法を見つけることができませんでしたが、それがおそらく最後の懸念事項です。

// lightbox keyboard navigation
function getFocusList() {
    return $('body,#lightbox *:visible').filter(function(idx,elm) {
        if ($(elm).is('body')) return true;
        if (/^hidden$/i.test($(elm).css('visibility'))) return false;
        return (
            (/^a(rea)?$/i.test(elm.nodeName) && $(elm).hasAttr('href') && !$(elm).is('.disabled')) ||
            (/^(input|textarea|button|select)$/i.test(elm.nodeName) && !$(elm).prop('disabled')) ||
            (/^\d+$/.test($(elm).prop('tabindex')) && !$(elm).prop('disabled') && !$(elm).is('.disabled'))
        )
    });
}
function globalKeyDown(e) {
    var
        LB          = !!$('#lightbox').length,
        isTAB       = e.which == 9,
        isSHIFT     = e.which == 16,
        SHIFT_ON    = LB && typeof $('#lightbox').data('SHIFT_ON') != 'undefined'
    if (isSHIFT && LB) $('#lightbox').data('SHIFT_ON',true);
    if (!isTAB || !LB) return;
    var focusList = getFocusList(), nextIndex;
    var curIndex = $.inArray($(this).get(0),focusList);
    if (SHIFT_ON) nextIndex = --curIndex == 0 ? focusList.length - 1 : curIndex;
    else nextIndex = ++curIndex == focusList.length ? (focusList.length > 1 ? 1 : 0) : curIndex;
    var next = $(focusList[nextIndex]);
    e.preventDefault();
    e.stopImmediatePropagation();
    next.focus();
}
function globalKeyUp(e) {
    var
        LB          = !!$('#lightbox').length,
        isSHIFT     = e.which == 16,
        SHIFT_ON    = LB && typeof $('#lightbox').data('SHIFT_ON') != 'undefined'
    if (isSHIFT && SHIFT_ON) $('#lightbox').removeData('SHIFT_ON')
}

$.fn.extend({
    hasAttr:function(attrStr) {
        var res = true;
        $(this).each(function() {
            if (typeof $(this).attr(attrStr) == 'undefined') res = false;
        });
        return res;
    }
});
$(document).ready(function() {
    $('body')
    .on('focus','#lightbox a',function() {$(this).addClass('hover')})
    .on('blur','#lightbox a',function() {$(this).removeClass('hover')})
    .on('keydown','*',globalKeyDown).on('keyup','*',globalKeyUp)
    .on('keydown',globalKeyDown).on('keyup',globalKeyUp)
    // remaining jQuery code...
});

これにより、同様の問題を抱えている他の人の時間を節約できることを願っています。

于 2012-09-16T02:34:55.443 に答える
0

イベントのネイティブな伝播順序を操作する唯一の方法は、DOMの順序を変更することです。DOM構造を一方向に残して、DOM構造とは何らかの形で異なるカスタム伝播順序を指定することはできません。イベントはDOMをバブルアップします。これが、ブラウザがイベントの伝播を行う方法です。

ライトボックスがページ全体をカバーするようにし(絶対位置、ページ全体でz-indexが高い)、キーボードフォーカスをドキュメントに設定して、ライトボックスとドキュメント以外の他の要素が入力イベントを取得しないようにすることができます。これは、ライトボックスオーバーレイで通常行われることです。他の要素をカバーしている場合(部分的に透明であっても)、すべてのマウスクリックをインターセプトします。次に、キーボードフォーカスをドキュメントに設定すると、キーイベントがページ内の要素に移動しないか、そのように機能するように設定できます。ライトボックスをこのように配置し、ライトボックスの下にあるものがキーボードフォーカスを取得しないようにすると、最初の伝播順序を取得する必要があります。

実例: http: //jsfiddle.net/jfriend00/q3r78/

この例には、他のフィールドにタブで移動できないように、キーストロークのデフォルトの処理を防ぐコードも含まれています。

于 2012-09-13T23:39:16.033 に答える