javascript 箭头键通过 li 导航(没有 jquery)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33790668/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 16:54:59  来源:igfitidea点击:

arrow keys navigation through li (no jquery)

javascripthtmlcssajaxautocomplete

提问by nxet

I'm trying to figure out a way to create an extremely basic autocomplete without 3rd parties dependencies. so far I've gotten to populate a list of results with an ajax call, and with mouse onclick events on each li the script completes the fields as supposed.
what I need to implement is an up/down/enter keys navigation system based on pure js, and after hours spent searching I gave up. this fiddleexplains quite perfectly my situation, with the difference that it does require jQuery.

我试图找出一种方法来创建一个非常基本的自动完成,而无需 3rd 方依赖。到目前为止,我已经使用 ajax 调用填充了一个结果列表,并且在每个 li 上使用鼠标 onclick 事件脚本完成了预期的字段。
我需要实现的是一个基于纯js的上/下/回车键导航系统,经过几个小时的搜索我放弃了。这个小提琴非常完美地解释了我的情况,不同之处在于它确实需要 jQuery。

I'd rather not paste any of my own code here as the final aim is learning the process, but since I'm linking to jsfiddle I'm required to so here's the fiddle.

我宁愿不在这里粘贴我自己的任何代码,因为最终目标是学习这个过程,但是由于我要链接到 jsfiddle,所以我需要这样做,所以这里是小提琴。

fiddle HTML:

小提琴HTML:

<div id="MainMenu">
    <ul>
        <li class="active"><a href="#">PATIENT TEST</a></li>
        <li><a href="#">QC TEST</a></li>
        <li><a href="#">REVIEW RESULTS</a></li>
        <li><a href="#">OTHER</a></li>
    </ul>
</div>

<a href="#" id="btnUp">Up</a>
<a href="#" id="btnDown">Down</a>

fiddle JS:

小提琴JS:

$(document).ready(function () {
    $('#btnDown').click(function () {
        var $current = $('#MainMenu ul li.active');
        if ($current.next().length > 0) {
            $('#MainMenu ul li').removeClass('active');
            $current.next().addClass('active');
        }
    });

    $('#btnUp').click(function () {
        var $current = $('#MainMenu ul li.active');
        if ($current.prev().length > 0) {
            $('#MainMenu ul li').removeClass('active');
            $current.prev().addClass('active');
        }
    });

    $(window).keyup(function (e) {
        var $current = $('#MainMenu ul li.active');
        var $next;

        if (e.keyCode == 38) {
            $next = $current.prev();
        } else if (e.keyCode == 40) {
             $next = $current.next();
        }

        if ($next.length > 0) {
            $('#MainMenu ul li').removeClass('active');
            $next.addClass('active');
        }
    });

});

thanks a lot in advance to anyone willing to point me in the right direction.

非常感谢任何愿意为我指明正确方向的人。

回答by nxet

This turned out to be simpler than I expected, and I've came up with the following code which appearently does the job quite well.

结果证明这比我预期的要简单,我想出了以下代码,它似乎很好地完成了这项工作。

Things to take in account are:

需要考虑的事项是:

  • the HTML attribute 'tabindex' must be specified on each element for the .focus() to be applied
  • to have a ENTER->submit feeling, you MUST target a link element within the li (still, I'm achieving this with onclick events not included here)
  • this works with an extremely simple list structure, so far I haven't tested it with nested dropdown menus
  • Note:this is most likely not suitable for a copy/paste situation, but as far as I can tell this method is procedurally currect, and can get you started developing more complex solutions
  • 必须在要应用的 .focus() 的每个元素上指定 HTML 属性“tabindex”
  • 要获得 ENTER->submit 的感觉,您必须在 li 中定位一个链接元素(不过,我正在通过此处未包含的 onclick 事件来实现此目的)
  • 这适用于非常简单的列表结构,到目前为止我还没有使用嵌套下拉菜单对其进行测试
  • 注意:这很可能不适合复制/粘贴情况,但据我所知,此方法在程序上是正确的,可以让您开始开发更复杂的解决方案

This is the basic HTML:

这是基本的 HTML:

<input type="text" name="main_input" id="input" />
<ul id="list">
 <li class="listElement"><a href="#" tabindex="1">li content</a></li>
 <li class="listElement"><a href="#" tabindex="1">li content</a></li>
 <li class="listElement"><a href="#" tabindex="1">li content</a></li>
</ul>

And here's the JS function, triggered when the list above is populated and shown:

这是 JS 函数,当上面的列表被填充和显示时触发:

    function scrollList() {
      var list = document.getElementById('list'); // targets the <ul>
      var first = list.firstChild; // targets the first <li>
      var maininput = document.getElementById('input');  // targets the input, which triggers the functions populating the list
      document.onkeydown = function(e) { // listen to keyboard events
        switch (e.keyCode) {
          case 38: // if the UP key is pressed
            if (document.activeElement == (maininput || first)) { break; } // stop the script if the focus is on the input or first element
            else { document.activeElement.parentNode.previousSibling.firstChild.focus(); } // select the element before the current, and focus it
            break;
          case 40: // if the DOWN key is pressed
            if (document.activeElement == maininput) { first.firstChild.focus(); } // if the currently focused element is the main input --> focus the first <li>
            else { document.activeElement.parentNode.nextSibling.firstChild.focus(); } // target the currently focused element -> <a>, go up a node -> <li>, select the next node, go down a node and focus it
          break;
        }
      }
    }

Apologies in advance for the kinda chaotic layout of the code, the function I came up with is a bit more complex and I've stripped out most of it for explaination purposes.

提前为代码有点混乱的布局道歉,我想出的函数有点复杂,为了解释的目的,我已经去掉了大部分。

Needless to say, I'm looking forward any comment about the solution above, in regard of errors, improvements or known compatibility issues.

不用说,我期待对上述解决方案的任何评论,包括错误、改进或已知的兼容性问题。

回答by Chaim Gluck

you wrote

你写了

tabindex="1"

标签索引=“1”

Why not just tabindex="0"? Using a positive umber greater than 0 is only needed if you want to cahnge the default order of navigation.

为什么不只是 tabindex="0"?仅当您想更改默认导航顺序时才需要使用大于 0 的正数。