【问题标题】:How do I achieve arrow key navigation between divs如何实现 div 之间的箭头键导航
【发布时间】:2015-04-16 13:23:30
【问题描述】:

我有以下 div 列表

<div id="multi-picker">
  <div id="opt1">
     <input type="checkbox">  Option 1
  </div>
  <div id="opt2">
     <input type="checkbox">  Option 2
  </div>
  etc...
</div>

一切正常,但我对键盘导航不满意。要从 opt1 导航到 opt2,我需要按 Tab 键。理想情况下,我想将选项视为选择并使用向上/向下箭头导航。这个可以吗?

或者... 有没有什么办法可以用复选框样式的选项进行多选以反映每个选项的选择状态?

【问题讨论】:

标签: html css


【解决方案1】:

我认为您将需要 javascript,并且使用插件是完成任务维护跨浏览器功能的更简单方法。但是,这里有一个fiddle,我认为,它只使用 javascript 就可以满足您的需求。它在您的选择元素上定义了附加属性,并使用 onkeydown 函数来处理元素之间的导航。

function keyPressed(e) {
    var srcElement = e.target;    // get the element that fired the onkeydown function
    var dataset = false;
    var selectList = false;
    var next = "";
    var prev = "";
    if (srcElement.dataset) {        // can we use HTML5 dataset?
        dataset = true;              // remember for later
        // is this an element for which we care
        if (srcElement.dataset.selectlist == 'true') {
            selectList = true;
        }
    } else {    // can't use HTML5 dataset, use getAttribute
        if (srcElement.getAttribute('data-selectlist') == 'true') {
            selectList = true;
        }
    }
    // is it a select element and the user pressed either up arrow or down arrow
    if (selectList && (e.keyCode == '38' || e.keyCode == '40')) {
        // get the next and prev navigation options for this element
        if (dataset) {
            next = srcElement.dataset.next;
            prev = srcElement.dataset.prev;
        } else {
            next = srcElement.getAttribute('data-next');
            prev = srcElement.getAttribute('data-prev');
        }
        // up arrow was pressed and a prev element is defined
        if (e.keyCode == '38' && prev != '') {
            document.getElementById(prev).focus();
        }
        // down arrow was pressed and a next element is defined
        if (e.keyCode == '40' && next != '') {
            document.getElementById(next).focus();
        }
        // don't do native processing of the up or down arrow (page scrolling)
        e.preventDefault;
    }
}
document.onkeydown = keyPressed;

这是包含附加元素的新 html:

<div id="multi-picker">
    <div id="opt1">
        <input id="select1" type="checkbox" data-selectlist="true" data-prev="" data-next="select2">  Option 1
    </div>
    <div id="opt2">
        <input id="select2" type="checkbox" data-selectlist="true" data-prev="select1" data-next="">  Option 2
    </div>
</div>

此代码针对所提出的问题非常具体,尽管它可能会解决问题,但使用通用插件可能会更好,该插件允许在您的环境中进行更通用的应用程序。您还可能会遇到与用户期望向下和向上箭头键执行的操作与您通过拦截它们执行的操作相关的问题。

根据我的经验,我遇到过这样的问题:不同的浏览器甚至不同的最终用户平台向应用程序呈现不同的行为,从而导致实现一致性参差不齐。许多插件旨在消除这种不一致并提供更简洁、更直观的界面。

【讨论】:

    【解决方案2】:

    或者...有没有办法让带有复选框样式的选项进行多选以反映每个选项的选择状态?

    multi-browser 支持吗?并不真地。但是,如果您是“它在 Chrome 中工作,它可以发布!”类型的开发者,那么您完全可以伪造 multi select 以显示具有反映每个选项的选择状态的复选框好啊CSS

    首先是我们的 HTML:

    <select multiple="multiple">
        <option>Hello</option>
        <option>World</option>
        <option>Hello</option>
        <option>World</option>
    </select>
    

    接下来,dat CSS:

    select {
        border: none;
    }
    select:focus {
        outline: none;
    }
    select option:before {
        display: inline-block;
        content: '';
        width: 13px;
        height: 13px;
        position: relative;
        margin-right: 3px;
        background-image: url('http://i.imgur.com/5xszy3H.png');
        background-position: -40px 0px;
        top: 2px;
    }
    

    使用generated content,我们现在已经应用了我们的pseudo checkboxes。让我们添加最后一点 CSS 给我们一个正确的selected 状态!

    select option:checked:before {
        background-position: -40px -40px;
    }
    

    哎呀。

    这是一个可以玩弄的小提琴:http://jsfiddle.net/9tLz6ugz/

    在(有限)测试中,这似乎只适用于 Chrome 和 FireFox(都是 OSX 上的最新版本)。 Safari、IE 和 Opera 一起忽略了生成的内容。所以,虽然不实用(至少今天不可行),但还是可行的!

    (这是另一个没有background-image 的小提琴 - 需要更多的工作才能使浏览器的外观/感觉保持一致:http://jsfiddle.net/wpch98tg/ 但确实演示了使用unicode 在多选中伪造“复选框” ...)

    【解决方案3】:

    我不相信你会找到一种使用纯 HTML 和 CSS 的方法——这对于自定义核心功能来说太过分了,所以一点 JavaScript 就可以解决问题(我也使用 jQuery 让它稍微简单一些)。

    在我的测试中,我使用 &lt;label&gt; 而不是 &lt;div&gt; 来包装复选框,但同样的想法也适用于 div。我只是更喜欢标签,所以如果 JavaScript 没有加载,复选框仍然是可点击的。

    <div class="fake-select">
        <label for="fs1"><input type="checkbox" id="fs1" name="fs1" />Fake 1</label>
        <label for="fs2"><input type="checkbox" id="fs2" name="fs2" />Fake 2</label>
        [ ... ]
    </div>
    

    基本上,您需要跟踪用户的按键和“活动”输入。查找向上/向下箭头键并根据它更改活动输入(滚动到它,为样式添加类名)。我还允许空格键选中/取消选中当前活动的框。

    var fs = $(".fake-select"),
        items = fs.find('input'),
        divs = fs.find('label'),
        active = 0;
    
    // Hook keypresses
    fs.keydown( function(e){
        reCalculate(e);
        rePosition();
        return false;
    });
    
    // Click event for manual changes
    items.unbind('click').click(function(e){
        var thisInput = $(this),
            thisLabel = $(this).parent();
        window.active = thisLabel.index();
    
        thisLabel.removeClass("checked");
        if (thisInput.is(":checked"))
            thisLabel.addClass("checked");
    
        rePosition();
    });
    
    // Set new active element based on keypress
    //    Trigger click event if user hits space bar
    function reCalculate(e){
        var max = items.length -1,
            cur = window.active,
            charCode = (typeof e.which == "number" && e.which) ? e.which : e.keyCode;
    
        if (charCode == 38) { // move up
            cur--;
            cur = (cur <= 0) ? 0 : cur;
        }
        if (charCode == 40) { // move down
            cur++;
            cur = (cur >= max) ? max : cur;
        }
        if (charCode == 32) { // space bar
            items.eq(cur).focus().trigger('click');
        }
        window.active = cur;
    }
    
    // Add active class, call scroll function
    function rePosition(){
        divs.removeClass('active').eq(window.active).addClass('active');
        scrollInView();
    }
    
    // Scroll the list so the active element is in view
    function scrollInView(){
        var target = divs.eq(window.active);
        if (target.length) {
            var top = fs.scrollTop() + target.position().top - fs.height()/2 + target.height()/2
    
            fs.stop().animate({scrollTop: top}, 400);
        }
        return false;
    }
    

    jsFiddle 示例:http://jsfiddle.net/daCrosby/kqecngv0/13/

    【讨论】:

      【解决方案4】:

      你会使用 jQuery 吗?这将通过向上/向下箭头激活焦点功能

      function focusOnCheckboxes(locator){
      
      var checkboxes = jQuery(locator).find(':checkbox');
      var index = 0;
      
      jQuery(locator).on('keydown', function(e){
          if(  e.keyCode == 38 ){
              if(index > 0){
                  index = index - 1;
              }
              checkboxes[index].focus();
          }
          else if(e.keyCode == 40){
              if(index < checkboxes.length - 1){
                 index = index + 1;     
              }
              else{
                   index = checkboxes.length - 1;   
              }
              checkboxes[index].focus();
          }
          else{
              //console.log(e.keyCode);
          }
      });
      }
      
      // set the locator
      focusOnCheckboxes('body');
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-14
        • 1970-01-01
        • 2012-11-26
        • 1970-01-01
        • 2015-07-21
        相关资源
        最近更新 更多