繁体   English   中英

使用箭头键浏览列表? (JavaScript/JQ)

[英]Navigate through list using arrow keys? (JavaScript/JQ)

我似乎无法找到如何实现这一点的答案,但这是我多次见过的功能。 本质上,我正在回显一个列表,我想创建使用箭头键/输入突出显示和选择这些项目的能力。 有人可以帮助我了解如何实现这一目标吗? 我知道如何使用键码(当然),只是不知道如何将其转换为用于选择列表中项目的功能代码......

我在想也许我必须有某种隐藏的单选按钮才能将其标记为已选中……但即便如此,我也不知道如何从一个单选按钮跳到另一个在列表中上下. 因此,如果有人能帮我解决这个问题,我将不胜感激。 谢谢你。

由于您没有真正解释您遇到的问题,我只是创建了一个通用解决方案。 希望这有助于:

var li = $('li');
var liSelected;
$(window).keydown(function(e) {
    if(e.which === 40) {
        if(liSelected) {
            liSelected.removeClass('selected');
            next = liSelected.next();
            if(next.length > 0) {
                liSelected = next.addClass('selected');
            } else {
                liSelected = li.eq(0).addClass('selected');
            }
        } else {
            liSelected = li.eq(0).addClass('selected');
        }
    } else if(e.which === 38) {
        if(liSelected) {
            liSelected.removeClass('selected');
            next = liSelected.prev();
            if(next.length > 0) {
                liSelected = next.addClass('selected');
            } else {
                liSelected = li.last().addClass('selected');
            }
        } else {
            liSelected = li.last().addClass('selected');
        }
    }
});

JSFiddle: http : //jsfiddle.net/Vtn5Y/

我的原生 JavaScript 示例

 var ul = document.getElementById('list'); var liSelected; var index = -1; document.addEventListener('keydown', function(event) { var len = ul.getElementsByTagName('li').length-1; // DOWN ARROW if(event.which === 40) { index++; if (liSelected) { removeClass(liSelected, 'selected'); next = ul.getElementsByTagName('li')[index]; if(typeof next !== undefined && index <= len) { liSelected = next; } else { index = 0; liSelected = ul.getElementsByTagName('li')[0]; } addClass(liSelected, 'selected'); console.log(index); } else { index = 0; liSelected = ul.getElementsByTagName('li')[0]; addClass(liSelected, 'selected'); } } // UP ARROW else if (event.which === 38) { if (liSelected) { removeClass(liSelected, 'selected'); index--; next = ul.getElementsByTagName('li')[index]; if(typeof next !== undefined && index >= 0) { liSelected = next; } else { index = len; liSelected = ul.getElementsByTagName('li')[len]; } addClass(liSelected, 'selected'); } else { index = 0; liSelected = ul.getElementsByTagName('li')[len]; addClass(liSelected, 'selected'); } } }, false); function removeClass(el, className) { if(el.classList) { el.classList.remove(className); } else { el.className = el.className.replace(new RegExp('(^|\\\\b)' + className.split(' ').join('|') + '(\\\\b|$)', 'gi'), ' '); } }; function addClass(el, className) { if(el.classList) { el.classList.add(className); } else { el.className += ' ' + className; } };
 li.selected {background:yellow}
 <ul id="list"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> <li>Item 4</li> </ul>

https://jsfiddle.net/m6watqpe/

2020 更新

如果有人想在Vue.js 中做到这一点,我在下面的代码中添加了必要的注释,其余的都是不言自明的

HTML

<script type="text/x-template" id="list">
  <div id="list-container" ref="root">
    <div v-for="item in items" :key="item.id" class="list-item" :class="item.id === selectedId ? 'selected': ''" @click="select(item.id)">
      {{item.value}}
    </div>
  </div>
</script>

<div id="app">
  <list></list>
</div>

CSS

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

html {
  height: 100%;
}

body {
  height: 100%;
  min-height: 100%;
  padding: 1rem;
  font-family: 'Tahoma', sans-serif;
}

.list-item {
  padding: 1rem 0.25rem;
}

.selected {
  background: lightyellow;
}

JS

const items = new Array(100).fill(null).map((item, index) => {
  return { id: index, value: "Item " + index };
});

// https://stackoverflow.com/questions/5685589/scroll-to-element-only-if-not-in-view-jquery
function scrollIntoViewIfNeeded(target) {
    var rect = target.getBoundingClientRect();
    if (rect.bottom > window.innerHeight) {
        target.scrollIntoView(false);
    }
    if (rect.top < 0) {
        target.scrollIntoView();
    } 
}

Vue.component("list", {
  template: "#list",
  data() {
    return {
      items,
      selectedId: 0
    };
  },
  methods: {
    select(itemId) {
      this.selectedId = itemId;
      scrollIntoViewIfNeeded(this.$refs.root.children[itemId])
      // this.$refs.root.children[item.id].scrollIntoView({ behavior: "smooth" });
    },
    handleKeyDown(event) {
      switch (event.keyCode) {
        // In case of left arrow key move to the last item
        case 37:
          if (this.selectedId > 0) {
            this.select(this.selectedId - 1);
          }
          // Prevent the default scroll event from firing
          event.preventDefault();
          break;
        // In case of up arrow key, move to the last item
        case 38:
          if (this.selectedId > 0) {
            this.select(this.selectedId - 1);
          }
          event.preventDefault();
          break;
        // In case of right arrow key, move to the next item
        case 39:
          if (this.selectedId < this.items.length - 1) {
            this.select(this.selectedId + 1);
          }
          event.preventDefault();
          break;
        // In case of down arrow key, move to the next item
        case 40:
          if (this.selectedId < this.items.length - 1) {
            this.select(this.selectedId + 1);
          }
          event.preventDefault();
          break;
      }
    }
  },
  mounted() {
    window.addEventListener("keydown", this.handleKeyDown);
  },
  destroyed() {
    window.removeEventListener("keydown", this.handleKeyDown);
  }
});

new Vue({
  el: "#app"
});

这可能取决于浏览器。 它似乎只有在无线电输入彼此相邻时才有效(标签也可以)。

<input type="radio" ... /> 
<input type="radio" ... />
<input type="radio" ... />

但这会破坏 Firefox 和其他浏览器中的无线电导航:

<div><input type="radio" ... /> ... </div>
<div><input type="radio" ... /> ... </div>

一旦你想让一些东西比简单的列表(类别……)更复杂一些,这就会很烦人。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM