使用箭头键浏览列表?(JavaScript/JQ)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8902787/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Navigate through list using arrow keys? (JavaScript/JQ)
提问by Ian
I can't seem to find an answer to how to accomplish this, yet it's a feature I've seen several times. Essentially I'm echoing out a list and I would like to create the ability to highlight and select these items using arrow keys/enter. Can someone help give me an idea as to how I can accomplish this? I know how to use keycodes (of course), just not how to turn that into functioning code for selecting items on a list...
我似乎无法找到如何实现这一点的答案,但这是我多次见过的功能。本质上,我正在回显一个列表,我想创建使用箭头键/输入突出显示和选择这些项目的能力。有人可以帮助我了解如何实现这一目标吗?我知道如何使用键码(当然),只是不知道如何将其转换为用于选择列表中项目的功能代码......
I was thinking maybe I'd have to have some sort of hidden radio button to mark it as selected or not... but even then I don't know how I would jump from one radio button to the other up and down the list. So if anyone could give me a hand with this I'd really appreciate it. Thank you.
我在想,也许我必须有某种隐藏的单选按钮才能将其标记为已选中……但即便如此,我也不知道如何在列表中从一个单选按钮跳到另一个. 因此,如果有人能帮我解决这个问题,我将不胜感激。谢谢你。
回答by maxedison
Since you didn't really explain what you're having trouble with, I just created a general solution. Hopefully this helps:
由于您没有真正解释您遇到的问题,我只是创建了一个通用解决方案。希望这有助于:
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/
JSFiddle:http: //jsfiddle.net/Vtn5Y/
回答by Falselight
My example for native JavaScript
我的原生 JavaScript 示例
var ul = document.getElementById('list');
var liSelected;
var index = -1;
document.addEventListener('keydown', function(event) {
var len = ul.getElementsByTagName('li').length-1;
if(event.which === 40) {
index++;
//down
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');
}
}
else if (event.which === 38) {
//up
if (liSelected) {
removeClass(liSelected, 'selected');
index--;
console.log(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>
回答by PirateApp
2020 Update
2020 更新
In case someone wants to do this in Vue.js, I have added the code below with comments wherever necessary and rest is self explanatory
如果有人想在Vue.js 中做到这一点,我在下面的代码中添加了必要的注释,其余的都是不言自明的
HTML
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
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
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"
});
回答by Christophe Roussy
This may depend on the browser. It seems to work only if the radio inputs are next to each other (label is also ok).
这可能取决于浏览器。它似乎只有在无线电输入彼此相邻时才有效(标签也可以)。
<input type="radio" ... />
<input type="radio" ... />
<input type="radio" ... />
But this will break radio navigation in Firefox and probably other browsers:
但这会破坏 Firefox 和其他浏览器中的无线电导航:
<div><input type="radio" ... /> ... </div>
<div><input type="radio" ... /> ... </div>
This is annoying as soon as you want to make something a bit more complex than a simple list (categories...).
一旦你想让一些东西比简单的列表(类别……)更复杂一些,这就会很烦人。