【问题标题】:Make ul list work like select input使 ul list 像选择输入一样工作
【发布时间】:2023-03-28 14:52:02
【问题描述】:

出于样式原因,我希望能够使用 ul 列表作为选择表单元素。

我可以用我的代码(不包括在这个 jsfiddle 中)填充一个隐藏的输入,到目前为止一切都很好。但是现在我试图让我的 ul 在按下键盘时表现得像选择输入,或使用鼠标。

在我之前的问题中,我在键盘控制方面遇到了一些问题。它们现在已修复。见:Autoscroll on keyboard arrow up/down

剩下的问题是按下键盘按钮时鼠标没有被忽略。这导致“悬停效果”首先听键盘输入,但不是立即转到鼠标并选择此 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');
        }
    }
});

那么任何人都可以教我如何在按下键盘按钮时忽略鼠标,但在用户再次触摸鼠标时列出鼠标。就像默认的选择输入表单字段一样。

更新

这是一个新的jsfiddle

【问题讨论】:

  • 你了解jqTransform等插件吗? dfc-e.com/metiers/multimedia/opensource/jqtransform
  • 感谢 Lee 的建议,我知道这样的插件。但我认为我真的需要一个 ul,因为独特的“点击”按钮。我已经更新了我的 jsfiddle:jsfiddle.net/JVDXT/4,如您所见,我想跨越按钮内的选定值。使用其中一个插件可以做到这一点吗?
  • 只是为了让你知道(以防你不知道),choose.js 和 select2,非常好的和灵活的 DropDowns 替代品
  • 选择输入因浏览器而异
  • 感谢所有的反应,但我仍然更喜欢“轮播”类型的选择。突出显示的字段尽可能位于中心的位置 =)

标签: javascript jquery html


【解决方案1】:

看看这个:

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();

关键是鼠标悬停解除绑定,鼠标移动时重新绑定。

我通过使用闭包函数对其进行了一些重构,将逻辑添加到名为 dropdown 的 jQuery 方法中,以便您可以重用它,使用 switch 而不是一堆 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 并使其表现得像一个选择以避免悬停问题,对吗?

【讨论】:

    【解决方案2】:

    这是一个解决方案,我正在使用mousemove,因为这将确保在鼠标再次开始移动时选择正确的列表项,mouseover 只有在输入新的时才会开始选择列表项列表项:

    取匿名函数并为其命名:

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

    声明一个全局变量mousemoved,表示鼠标是否已经移到文档上并将其设置为false,在mousemove上将其设置为true并将mousemove函数附加到mousemove 列表项上的事件。

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

    只要按下一个键(在 keydown 事件开始时),使用 jQuery 的 .off() 方法删除列表项上的 mousemove 事件(如果存在),并将 mousemoved 设置为 @987654336 @ 以确保在鼠标再次移动之前不会再次附加 mousemove 事件。

    jQuery(".btn-group").keydown(function(e) {
    
      $('.btn-group .dropdown-menu li').off('mousemove');
      mousemoved = false; 
      ... // Some more of your code
    

    这是一个jsFiddle

    【讨论】:

      【解决方案3】:

      我尝试通过阻止自动滚动、在 li 上添加 tabindex、将焦点设置为活动以及使用标志来抑制鼠标来解决您的问题。

      修复了小提琴: http://jsfiddle.net/8nKJT/ [修复了 Chrome 中的一个问题]

      http://jsfiddle.net/RDSEt/

      问题是因为在keydown 上触发的自动scroll 再次触发mouseenter 混淆了li 的选择。

      注意:与其他方法的区别(此处的答案)我注意到它在每次按键时滚动,而不是仅在到达顶部或底部后才滚动(正常行为)。当您并排查看演示时,您会感受到不同。

      以下是更改说明列表和一个小演示来解释它是如何修复的,

      查看演示和代码更改(添加了一些改进)并告诉我。

      也感谢你的问题,我在我写的一个插件中注意到了这个问题和一堆其他问题。

      几个月前我写了一个插件来过滤选项,它的作用也完全像一个下拉菜单。

      DEMO:http://jsfiddle.net/nxmBQ/ [将filterType 更改为'' 以关闭过滤]

      原插件页面为http://meetselva.github.io/combobox/

      .. 更多

      【讨论】:

        【解决方案4】:

        如果最近在小部件上按下了按键,您可以使用全局忽略 mouseover 事件。例如:

        var last_key_event = 0;
        
        jQuery(".btn-group .dropdown-menu li").mouseover(function() {
            if ((new Date).getTime() > last_key_event + 1000) {
                console.log('mousie')
                jQuery(".btn-group .dropdown-menu li").removeClass('selected');
                jQuery(this).addClass('selected');
            }
        });
        

        然后keydown处理程序可以设置它被处理的时间以避免与鼠标交互:

        //What to do when the keyboard is pressed
        jQuery(".btn-group").keydown(function(e) {
            last_key_event = (new Date).getTime();
            ...
        });
        

        last_key_event 变量单独用于每个小部件而不是全局变量可能是有意义的。

        【讨论】:

          【解决方案5】:

          你可以试试这个解决方案。如果坐标没有改变(自上次 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/

          【讨论】:

            【解决方案6】:

            方法 一个合理的解决方案应该模仿其他具有类似目的的 UI 元素的行为。在所有选中的系统(Windows、Linux、主要浏览器)上,下拉框的行为如下:

            将鼠标悬停在一个项目上会突出显示它。按箭头键更改所选元素,并相应滚动。移动鼠标选择下面的元素。如果选择为空,则按 down 选择第一个元素。按 up 选择最后一个元素。

            解决方案 这个code 说明了我模仿所描述行为的方法。不错不错,试试吧……

            其他注意事项还有许多其他选项可以抑制不必要的鼠标移动以更改所选元素。其中包括:

            • 保持上次输入法的状态。如果上次选择是使用键盘,则将鼠标悬停在元素上不会选择它,只有单击才会选择它
            • 如果坐标没有改变指定的距离,则忽略mouseover事件,例如10 像素
            • 如果用户曾经使用过键盘,则忽略mouseover

            但是,至少对于公众可以访问的应用程序,最好始终坚持已建立的 UI 模式。

            【讨论】:

              【解决方案7】:

              出现的问题是,当鼠标停留在展开列表的一部分上时,使用键进行的选择无效,因为键盘所做的选择会立即恢复到恰好位于鼠标下方的项目。

              您可以解决此问题并保留所有功能,而无需执行任何复杂的条件行为或删除任何事件处理程序。

              只需将您的 mouseover 事件处理程序更改为 mousemove 事件处理程序。这样,在用户使用键盘进行选择的任何时候,都会听到任何键盘导航和选择,并忽略鼠标位置。并且无论何时使用鼠标进行选择,都会听到鼠标的声音。

              这听起来微不足道,但它似乎使您的 JS Fiddle 表现完美,并且鼠标和键盘之间没有任何冲突行为。像这样:

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

              (您的代码保持不变,只是将 mouseover 替换为 mousemove)

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2013-06-17
                • 1970-01-01
                • 1970-01-01
                • 2013-10-14
                • 1970-01-01
                • 1970-01-01
                • 2018-07-19
                • 1970-01-01
                相关资源
                最近更新 更多