css 如何使用键盘箭头在下拉菜单中导航

1mrurvl1  于 2023-02-10  发布在  其他
关注(0)|答案(5)|浏览(167)

我有一个简单的下拉菜单,我想有用户可以通过键盘箭头(向上/向下)在下拉菜单导航的可能性。
下面是代码:

function myFunction() {
  document.getElementById("myDropdown").classList.toggle("show");
}

window.onclick = function(event) {
  if (!event.target.matches('.dropbtn')) {
    var dropdowns = document.getElementsByClassName("dropdown-content");
    var i;
    for (i = 0; i < dropdowns.length; i++) {
      var openDropdown = dropdowns[i];
      if (openDropdown.classList.contains('show')) {
        openDropdown.classList.remove('show');
      }
    }
  }
}
.dropbtn {
  background-color: #3498DB;
  color: white;
  padding: 16px;
  font-size: 16px;
  border: none;
  cursor: pointer;
}

.dropbtn:hover, .dropbtn:focus {
  background-color: #2980B9;
}

.dropdown {
  position: relative;
  display: inline-block;
}

.dropdown-content {
  display: none;
  position: absolute;
  background-color: #f1f1f1;
  min-width: 160px;
  overflow: auto;
  box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
  z-index: 1;
}

.dropdown-content a {
  color: black;
  padding: 12px 16px;
  text-decoration: none;
  display: block;
}

.dropdown a:hover {background-color: #ddd;}

.show {display: block;}
<div class="dropdown">
  <button onclick="myFunction()" class="dropbtn">Dropdown</button>
  <div id="myDropdown" class="dropdown-content">
    <a href="#home">Home</a>
    <a href="#about">About</a>
    <a href="#contact">Contact</a>
  </div>
</div>

当我使用tab时,这很好用,但是我想使用箭头(向上/向下),有人能帮我吗?

5uzkadbs

5uzkadbs1#

我会将侦听器添加到下拉列表及其内容中,而不是整个页面。
通过使用下拉列表的dataset属性存储选定的索引,可以对上一个/下一个子级调用focus()

const
  ARROW_UP = 38,
  ARROW_DOWN = 40;

const mod = (n, m) => ((n % m) + m) % m;

const navigateList = e => {
  const
    dropdown = e.target.closest('.dropdown'),
    selectedIndex = parseInt(dropdown.dataset.selectedIndex, 10),
    children = dropdown.querySelectorAll('.dropdown-content a');

  switch (e.which) {
    case ARROW_UP:
      focusDropdownChild(dropdown, mod(selectedIndex - 1, children.length));
      break;
    case ARROW_DOWN:
      focusDropdownChild(dropdown, mod(selectedIndex + 1, children.length));
      break;
  }
};

const toggleShow = (e) => {
  const
    button = e.target,
    dropdown = button.closest('.dropdown'),
    content = dropdown.querySelector('.dropdown-content');
  content.classList.toggle('show');
  focusDropdownChild(dropdown, 0);
};

const navigate = e => {
  const
    item = e.target,
    content = item.closest('.dropdown-content');
  console.log(`Navigating to... "${item.textContent}"`);
  content.classList.toggle('show');
  e.preventDefault();
  e.stopImmediatePropagation();
};

const focusDropdownChild = (dropdown, index) => {
  const children = dropdown.querySelectorAll('.dropdown-content a');
  children.forEach(child => child.classList.remove('dropdown-item-focus'));
  dropdown.dataset.selectedIndex = index;
  children[index].focus();
  children[index].classList.add('dropdown-item-focus');
};

const connectListeners = (dropdown) => {
  const
    button = dropdown.querySelector('.dropdown-button'),
    content = dropdown.querySelector('.dropdown-content'),
    children = content.querySelectorAll('a');
  button.addEventListener('click', toggleShow);
  content.addEventListener('keydown', navigateList);
  children.forEach(child => child.addEventListener('click', navigate));
};

const disconnectListeners = (dropdown) => {
  const
    button = dropdown.querySelector('.dropdown-button'),
    content = dropdown.querySelector('.dropdown-content'),
    children = content.querySelectorAll('a');
  button.removeEventListener('click', toggleShow);
  content.removeEventListener('keydown', navigateList);
  children.forEach(child => child.removeEventListener('click', navigate));
};

document.querySelectorAll('.dropdown').forEach(connectListeners);
.dropdown-button {
  background-color: #3498DB;
  color: white;
  padding: 16px;
  font-size: 16px;
  border: none;
  cursor: pointer;
}

.dropdown-button:hover,
.dropdown-button:focus {
  background-color: #2980B9;
}

.dropdown {
  position: relative;
  display: inline-block;
}

.dropdown-content {
  display: none;
  position: absolute;
  background-color: #f1f1f1;
  min-width: 160px;
  overflow: auto;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  z-index: 1;
}

.dropdown-content a {
  color: black;
  padding: 12px 16px;
  text-decoration: none;
  display: block;
}

.dropdown a:hover {
  background-color: #ddd;
}

.show {
  display: block
}

.dropdown-item-focus {
  background: yellow;
}
<div class="dropdown">
  <button class="dropdown-button">Dropdown</button>
  <div class="dropdown-content">
    <a href="#home">Home</a>
    <a href="#about">About</a>
    <a href="#contact">Contact</a>
  </div>
</div>
t1qtbnec

t1qtbnec2#

只需在下拉列表中添加keydown事件,使用焦点播放并取消滚动

var pos = 0;
var maxpos = 0;
function myFunction() {
   pos=0;
   document.getElementById("myDropdown").classList.toggle("show");
   maxpos = $("#myDropdown a").length - 1;
    var x = window.scrollX, y = window.scrollY;
    $("#myDropdown a").eq(pos).trigger("focus");
    window.scrollTo(x, y);
}

$("#myDropdown, .dropbtn").on("keydown", function(e){
  if(e.which == 40){//down 
    pos = pos == maxpos ? 0 : pos + 1;
    $("#myDropdown a").eq(pos).trigger("focus");
  }
  if(e.which == 38){//up 
    pos = pos == 0 ? maxpos : pos - 1;
    $("#myDropdown a").eq(pos).trigger("focus");
  }
  return false;//cancel scrolling
});

window.onclick = function(event) {
  if (!event.target.matches('.dropbtn')) {
     var dropdowns = document.getElementsByClassName("dropdown-content");
    var i;
    for (i = 0; i < dropdowns.length; i++) {
      var openDropdown = dropdowns[i];
      if (openDropdown.classList.contains('show')) {
        openDropdown.classList.remove('show');
      }
    }
  }
}
.dropbtn {
  background-color: #3498DB;
  color: white;
  padding: 16px;
  font-size: 16px;
  border: none;
  cursor: pointer;
}

.dropbtn:hover, .dropbtn:focus {
  background-color: #2980B9;
}

.dropdown {
  position: relative;
  display: inline-block;
}

.dropdown-content {
  display: none;
  position: absolute;
  background-color: #f1f1f1;
  min-width: 160px;
  overflow: auto;
  box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
  z-index: 1;
}

.dropdown-content a {
  color: black;
  padding: 12px 16px;
  text-decoration: none;
  display: block;
}

.dropdown a:hover, .dropdown a:focus{
background-color: #ddd;
}

.show {display: block;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="dropdown">
  <button onclick="myFunction()" class="dropbtn">Dropdown</button>
  <div id="myDropdown" class="dropdown-content">
    <a href="#home">Home</a>
    <a href="#about">About</a>
    <a href="#contact">Contact</a>
  </div>
</div>
mgdq6dx1

mgdq6dx13#

您可以编写一个函数来侦听击键(当下拉菜单打开时),确定键并相应地更改焦点。

hec6srdp

hec6srdp4#

function myFunction() {
  let i = 0; // iterate over children elements inside dropdown
  const dropdown = document.getElementById("myDropdown");
  const childs = dropdown.children; // get all dropdown elements
  dropdown.classList.toggle("show");
  // attach keyboard events
  window.addEventListener("keydown", event => {
    switch(event.code) {
      case "ArrowDown":
        for (let c of childs) 
          c.classList.remove('dropbtn-selected')
        childs[Math.abs(i) % childs.length].classList.add('dropbtn-selected');
         i++;
        break;
      case "ArrowUp":
        for (let c of childs) 
          c.classList.remove('dropbtn-selected')
        childs[Math.abs(i) % childs.length].classList.add('dropbtn-selected');
         i--;
        break;
    }
  if (event.isComposing || event.keyCode === 229) {
    return;
  }
  });
}
.dropbtn {
  background-color: #3498DB;
  color: white;
  padding: 16px;
  font-size: 16px;
  border: none;
  cursor: pointer;
}
.dropbtn-selected {
  background-color: #2980B9;
}
.dropbtn:hover, .dropbtn:focus {
  background-color: #2980B9;
}

.dropdown {
  position: relative;
  display: inline-block;
}

.dropdown-content {
  display: none;
  position: absolute;
  background-color: #f1f1f1;
  min-width: 160px;
  overflow: auto;
  box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
  z-index: 1;
}

.dropdown-content a {
  color: black;
  padding: 12px 16px;
  text-decoration: none;
  display: block;
}

.dropdown a:hover {background-color: #ddd;}

.show {display: block;}
<div class="dropdown">
  <button onclick="myFunction()" class="dropbtn">Dropdown</button>
  <div id="myDropdown" class="dropdown-content">
    <a href="#home">Home</a>
    <a href="#about">About</a>
    <a href="#contact">Contact</a>
  </div>
</div>

不要忘记在选择下拉选项并关闭后立即删除eventListener

cx6n0qe3

cx6n0qe35#

米哈尔玛
所以,通过在互联网上搜索(关键词“HTML5键盘导航下拉”),我发现了这个:https://dev.to/emmabostian/creating-a-custom-accessible-drop-down-3gmo
您可以在下拉列表周围使用一个元素。

<select>
<option value="">Value 1</option>
<option value="">Value 2</option>
<option value="">Value 3</option>
<option value="">Value 4</option>
</select>

可悲的是,这使得一些看起来很垃圾的样式,这就是文章的其余部分。

相关问题