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

时间:2022-02-26 17:26:17

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 fiddle explains quite perfectly my situation, with the difference that it does require jQuery.

我正在试图找到一种方法来创建一个非常基本的自动完成,而不需要第三方的依赖。到目前为止,我已经用ajax调用填充了结果列表,并且使用每个li上的鼠标onclick事件,脚本按预期完成字段。我需要实现的是一个基于纯js的up/down/enter键导航系统,经过几个小时的搜索,我放弃了。这个小提琴很好地解释了我的情况,不同之处在于它需要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.

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

2 个解决方案

#1


7  

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
  • 必须在每个要应用的.focus()元素上指定HTML属性“tabindex”
  • 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)
  • 要有一个ENTER->提交的感觉,您必须针对li中的一个链接元素(仍然,我是通过不包括在这里的onclick事件实现的)
  • 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
  • 注意:这很可能不适合复制/粘贴的情况,但是据我所知,这种方法是程序上的简化,可以让您开始开发更复杂的解决方案

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.

毫无疑问,我期待任何关于上述解决方案的评论,关于错误、改进或已知的兼容性问题。

#2


0  

you wrote

你写的

tabindex="1"

tabindex = " 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的正umber,如果您想确定导航的默认顺序。

#1


7  

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
  • 必须在每个要应用的.focus()元素上指定HTML属性“tabindex”
  • 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)
  • 要有一个ENTER->提交的感觉,您必须针对li中的一个链接元素(仍然,我是通过不包括在这里的onclick事件实现的)
  • 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
  • 注意:这很可能不适合复制/粘贴的情况,但是据我所知,这种方法是程序上的简化,可以让您开始开发更复杂的解决方案

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.

毫无疑问,我期待任何关于上述解决方案的评论,关于错误、改进或已知的兼容性问题。

#2


0  

you wrote

你写的

tabindex="1"

tabindex = " 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的正umber,如果您想确定导航的默认顺序。