18

スタイリング上の理由から、選択フォーム要素として ul リストを使用できるようにしたいと考えています。

私は自分のコード (この jsfiddle には含まれていません) を非表示の入力に入力することができますが、これまでのところはうまくいっています。使用されている。

以前の質問で、キーボード コントロールに問題がありました。それらは現在修正されています。参照:キーボードの矢印の上下の自動スクロール

残っている問題は、キーボード ボタンが押されたときにマウスが無視されないことです。これにより、「ホバー効果」が最初にキーボード入力をリッスンしますが、すぐにマウスに移動して、このliアイテムを選択済みとして選択します。

これは私の jsfiddle の例で見ることができます: http://jsfiddle.net/JVDXT/3/

私のJavaScriptコード:

// scrollTo plugin 
  $.fn.scrollTo = function( target, options, callback ){
  if(typeof options == 'function' && arguments.length == 2){ callback = options; options = target; }
  var settings = $.extend({
    scrollTarget  : target,
    offsetTop     : 100,
    duration      : 0,
    easing        : 'linear'
  }, options);
  return this.each(function(){
    var scrollPane = $(this);
    var scrollTarget = (typeof settings.scrollTarget == "number") ? settings.scrollTarget : $(settings.scrollTarget);
    var scrollY = (typeof scrollTarget == "number") ? scrollTarget : scrollTarget.offset().top + scrollPane.scrollTop() - parseInt(settings.offsetTop);
    scrollPane.animate({scrollTop : scrollY }, parseInt(settings.duration), settings.easing, function(){
      if (typeof callback == 'function') { callback.call(this); }
    });
  });
}


//My code
//The function that is listing the the mouse
jQuery(".btn-group .dropdown-menu li").mouseover(function() {
        console.log('mousie')
        jQuery(".btn-group .dropdown-menu li").removeClass('selected');
        jQuery(this).addClass('selected');
})  

//What to do when the keyboard is pressed
jQuery(".btn-group").keydown(function(e) {
    if (e.keyCode == 38) { // up
        console.log('keyup pressed');
        var selected = jQuery('.selected');
        jQuery(".btn-group .dropdown-menu li").removeClass('selected');
        if (selected.prev().length == 0) {
            selected.siblings().last().addClass('selected');
        } else {
            selected.prev().addClass('selected');
            jQuery('.btn-group .dropdown-menu').scrollTo('.selected');
        }
    }
    if (e.keyCode == 40) { // down
        console.log('keydown');
        var selected = jQuery('.selected');
        jQuery(".btn-group .dropdown-menu li").removeClass('selected');
        if (selected.next().length == 0) {
            selected.siblings().first().addClass('selected');
        } else {
            selected.next().addClass('selected');
            jQuery('.btn-group .dropdown-menu').scrollTo('.selected');
        }
    }
});

それで、キーボードのボタンが押されたときにマウスを無視する方法を誰かに教えてもらえますが、ユーザーが再び触れたときにマウスにリストします。デフォルトの select 入力フォーム フィールドと同様です。

アップデート

これが新しいjsfiddleです。

4

7 に答える 7

13

これをチェックしてください:

http://jsfiddle.net/coma/9KvhL/25/

(function($, undefined) {

    $.fn.dropdown = function() {

        var widget = $(this);
        var label = widget.find('span.valueOfButton');
        var list = widget.children('ul');
        var selected;
        var highlighted;

        var select = function(i) {

            selected = $(i);
            label.text(selected.text());

        };

        var highlight = function(i) {

            highlighted = $(i);

            highlighted
            .addClass('selected')
            .siblings('.selected')
            .removeClass('selected');
        };

        var scroll = function(event) {

            list.scrollTo('.selected');

        };

        var hover = function(event) {

            highlight(this);

        };

        var rebind = function(event) {

            bind();

        };

        var bind = function() {

            list.on('mouseover', 'li', hover);
            widget.off('mousemove', rebind);

        };

        var unbind = function() {

            list.off('mouseover', 'li', hover);
            widget.on('mousemove', rebind);

        };

        list.on('click', 'li', function(event) {

            select(this);

        });

        widget.keydown(function(event) {

            unbind();

            switch(event.keyCode) {

                case 38:
                    highlight((highlighted && highlighted.prev().length > 0) ? highlighted.prev() : list.children().last());

                    scroll();
                    break;

                case 40:
                    highlight((highlighted && highlighted.next().length > 0) ? highlighted.next() : list.children().first());

                    scroll();
                    break;

                case 13:
                    if(highlighted) {

                        select(highlighted);

                    }
                    break;

            }

        });

        bind();

    };

    $.fn.scrollTo = function(target, options, callback) {

        if(typeof options === 'function' && arguments.length === 2) {

            callback = options;
            options = target;
        }

        var settings = $.extend({
            scrollTarget  : target,
            offsetTop     : 185,
            duration      : 0,
            easing        : 'linear'
        }, options);

        return this.each(function(i) {

            var scrollPane = $(this);
            var scrollTarget = (typeof settings.scrollTarget === 'number') ? settings.scrollTarget : $(settings.scrollTarget);
            var scrollY = (typeof scrollTarget === 'number') ? scrollTarget : scrollTarget.offset().top + scrollPane.scrollTop() - parseInt(settings.offsetTop, 10);

            scrollPane.animate({scrollTop: scrollY}, parseInt(settings.duration, 10), settings.easing, function() {

                if (typeof callback === 'function') {

                    callback.call(this);
                }

            });

        });

    };

})(jQuery);

$('div.btn-group').dropdown();

重要なのは、マウスオーバーのバインドを解除し、マウスが移動したときに再バインドすることです。

クロージャ関数を使用して少しリファクタリングし、ドロップダウンと呼ばれる jQuery メソッドにロジックを追加して、if などの束の代わりにスイッチを使用して再利用できるようにしました。

まあ、選択をリストに変換するプラグインは無数にあります:

http://ivaynberg.github.io/select2/

http://harvesthq.github.io/chosen/

http://meetselva.github.io/combobox/

そして私も私のものを持っています!( http://uniformjs.comと同じトリックを使用してタッチデバイスに対応)

https://github.com/coma/jquery.select

しかし、この質問は、その HTML を使用して、ホバーの問題を回避する選択のように動作させることに関するものですよね?

于 2013-05-12T15:55:47.420 に答える
2

ここに解決策があります。mousemoveこれは、マウスが再び動き始めるとすぐに正しいリスト項目が選択されるようにするためですmouseover。新しいリスト項目を入力すると、リスト項目の選択が開始されます。

無名関数に名前を付けます。

function mousemove() {
  console.log('mousie')
  jQuery(".btn-group .dropdown-menu li").removeClass('selected');
  jQuery(this).addClass('selected');
}

mousemovedマウスがドキュメント上に移動したかどうかを示すグローバル変数を宣言して に設定し、ドキュメントfalsemousemoveで に設定してリスト項目のイベントに関数をtrueアタッチします。mousemovemousemove

var mousemoved = false;

jQuery(document).mousemove(function() {
  if(!mousemoved) {
    $('.btn-group .dropdown-menu li').mousemove(mousemove);  
    mousemoved = true;    
  }
})  

キーが押されるとすぐに (keydown イベントの開始時)、jQuery の.off()メソッドを使用mousemoveして、リスト項目にイベントが存在する場合はそれを削除し、 に設定mousemovedfalsemousemove、マウスが押されるまでイベントが再びアタッチされないようにします。再び移動しました。

jQuery(".btn-group").keydown(function(e) {

  $('.btn-group .dropdown-menu li').off('mousemove');
  mousemoved = false; 
  ... // Some more of your code

これがjsFiddle.

于 2013-05-11T14:45:56.783 に答える
0

表示される問題は、展開されたリストの一部の上にマウスを置いたままにすると、キーボードによる選択がマウスの下にあるアイテムにすぐに戻るため、キーを使用した選択が無効になることです。

この問題を解決し、複雑な条件付き動作を実行したり、イベント ハンドラーを削除したりすることなく、すべての機能を保持できます。

mouseover イベント ハンドラーを mousemove イベント ハンドラーに変更するだけです。このようにして、キーボードのナビゲーションと選択がリッスンされ、ユーザーがキーボードを使用して選択するときはいつでもマウスの位置が無視されます。そして、マウスが選択に使用されているときはいつでも、マウスはリッスンされます。

これは些細なことのように思えますが、JS Fiddle が完全に動作し、マウスとキーボードの間で競合する動作がないように思われます。このような:

//The function that is listening to the mouse
jQuery(".btn-group .dropdown-menu li").mousemove...

(コードは変更されず、mouseover を mousemove に置き換えるだけです)

于 2013-05-13T17:18:04.780 に答える
0

アプローチ合理的な解決策は、同様の目的を果たす他の UI 要素の動作を模倣する必要があります。オンになっているすべてのシステム (Windows、Linux、主要なブラウザー) で、ドロップダウン ボックスは次のように動作します。

項目にマウスを合わせると強調表示されます。矢印キーを押すと、選択した要素が変更され、それに応じてスクロールします。マウスを動かすと、下の要素が選択されます。選択が空の場合、 を押すdownと最初の要素が選択されます。を押すとup、最後の要素が選択されます。

解決策このコードは、説明されている動作を模倣するための私のアプローチを示しています。かっこいいですよね、やってみて…

その他の考慮事項不要なマウスの動きを抑制して選択した要素を変更するオプションは他にも多数あります。これらには以下が含まれます:

  • 最後の入力方法の状態を保持します。最後の選択がキーボードを使用していた場合、要素の上にカーソルを置いても選択されず、クリックするだけで選択されます
  • mouseover座標が指定された距離 (例: 10 ピクセル) だけ変化していない場合、イベントを無視します。
  • mouseoverユーザーがキーボードを使用したことがあるかどうかを無視する

ただし、少なくとも一般に公開されているアプリケーションの場合は、確立された UI パターンに固執することが常に最善です。

于 2013-05-11T19:49:56.250 に答える
0

この解決策を試すことができます。mousemove(最後の mousemove イベント以降) 座標が変更されていない場合、イベントは無視されます。

//The function that is listing the the mouse
var lastOffsets = "";

jQuery(".btn-group .dropdown-menu li").mouseover(function(e) {
        var curOffsets = e.clientX+":"+e.clientY;
        if(curOffsets == lastOffsets) {
           // mouse did not really move
            return false;
        }

        lastOffsets = curOffsets;

        ///// rest of your code
}

これがあなたが望んでいたものかどうかを確認するためにフィドルを更新しました: http://jsfiddle.net/pdW75/1/

于 2013-05-11T14:50:03.883 に答える