当 Flexbox 中的项目以 4 种方式可见时(左、上、右、下),在 Flexbox 中的项目之间导航

问题描述 投票:0回答:1

我有一个过滤器下拉列表,其中有一个搜索按钮,如果列表中没有项目,按钮就会激活 但是下拉列表中有多个项目在一行中,所以 我想要的是能够使用箭头键以各种方式在它们之间导航,并在按下 Enter 时打开它们的链接,当列表上没有项目时焦点返回到搜索按钮

我尝试过聆听让它工作,但我无法在 4 轴上做到这一点,它只能水平工作

这是代码:

document.addEventListener('click', function(event) {
  const ul = document.getElementById("tagList");
  const input = document.getElementById('search');

  if (!ul.contains(event.target) && event.target !== input) {
    ul.style.visibility = "hidden"
    input.style = "border-radius: 1px"
    input.style = "padding: 5px";
    enterBtn.style.display = "none"
  }
});

function searchMenu() {
  let input, filter, ul, li, a, i, txtValue;
  input = document.getElementById('search');
  filter = input.value.toUpperCase();
  ul = document.getElementById("tagList");
  li = ul.getElementsByTagName('li');
  enterBtn = document.getElementById('enterButton');

  // Check if there are no matching list items
  let noMatches = true;
  for (i = 0; i < li.length; i++) {
    a = li[i].getElementsByTagName("a")[0];
    txtValue = a.textContent || a.innerText;
    if (txtValue.toUpperCase().indexOf(filter) > -1) {
      li[i].style.display = "block"
      enterBtn.style.display = "none"
      noMatches = false; // When no match found, enable button
    } else {
      enterBtn.style = "background-color: #000000; color: #ffffff";
      enterBtn.style.display = "block"
      li[i].style.display = "none";
    }
  }

  // Show the itemwindow only if there are matches and disable advanced search to prevent the system from unnecessary datafetch from db
  if (!noMatches) {
    ul.style.visibility = "visible"
    input.style = "border: 3px solid #000000"
    input.style.margin = "0",
      enterBtn.style = "background-color: #f2f2f2; color: #ffffff; border: none; box-shadow: none;";
    enterBtn.disabled = true;
    enterBtn.style.display = "block";
    enterBtn.style.cursor = "default";
  } else {
    enterBtn.disabled = false;
    ul.style.visibility = "hidden"
    input.style = "border: 2pxsolid #000000";
    // Hide the taglist if no matches
  }
}

// Call searchMenu func initially to hide the taglist if there are no items to list
searchMenu();

// Click event listener to the search input to show the ul when clicked
const searchInput = document.getElementById('search');
searchInput.addEventListener('click', function(event) {;
  event.stopPropagation(); // Prevent the click event from reaching the doc click listener
  searchMenu(); // Call the searchMenu func again when the input is clicked
});
#smContainer {
  display: flex;
}

#searchBox {
  display: flex;
  justify-content: end;
  max-height: 100px;
  width: 400px;
}

#search {
  padding: 5px;
  outline: none;
  width: inherit;
  max-width: inherit;
}

#enterButton {
  position: absolute;
  border: 0.2rem solid #000000;
  background-color: #f2f2f2;
  color: rgb(0, 0, 0);
  display: none;
  cursor: pointer;
}

#tagList {
  margin: 30px auto;
  position: absolute;
  list-style-type: none;
  border: 1px solid #000000;
  background-color: white;
  visibility: hidden;
  display: flex;
  flex-wrap: wrap;
  width: 400px;
}

#tagList li a {
  padding: 2px 2px;
  text-decoration: none;
  color: #000000;
  display: block;
  border: 1px solid #000000;
  margin: 2px;
}

#tagList li a:hover {
  background-color: #000000;
  color: #ffffff;
}
<div id="smContainer">
  <div id="searchBox">
    <input type="text" id="search" autocomplete="off" onclick="searchMenu()" onkeyup="searchMenu()" placeholder="filterbox" />
    <button type="submit" id="enterButton">SEARCH</button>
    <ul id="tagList">

      <li><a href="#">Ipsum</a></li>
      <li><a href="#">Dolor</a></li>
      <li><a href="#">Sit</a></li>
      <li><a href="#">Amet</a></li>
      <li><a href="#">Amet</a></li>
      <li><a href="#">Dolor</a></li>
      <li><a href="#">Sit</a></li>
      <li><a href="#">Amet</a></li>
      <li><a href="#">Ipsum</a></li>
      <li><a href="#">Dolor</a></li>
      <li><a href="#">Sit</a></li>
      <li><a href="#">Amet</a></li>
      <li><a href="#">Amet</a></li>
      <li><a href="#">Dolor</a></li>
      <li><a href="#">Sit</a></li>
      <li><a href="#">Amet</a></li>
      <li><a href="#">Ipsum</a></li>
      <li><a href="#">Dolor</a></li>
      <li><a href="#">Sit</a></li>
      <li><a href="#">Amet</a></li>
      <li><a href="#">Amet</a></li>
      <li><a href="#">Dolor</a></li>
      <li><a href="#">Sit</a></li>
      <li><a href="#">Amet</a></li>
    </ul>
  </div>
</div>

javascript navigation dropdown arrow-keys
1个回答
0
投票

这是部分解决方案。它的工作原理是更新内部坐标 x 和 y,以对应屏幕上的位置。

此外,值得注意的是,您应该使用

display:grid
而不是
display:flex
在网格中设置项目。

除了这里的内容之外,您还需要找到一种方法来根据您的选择动态设置坐标、xMax 和 yMax 的边界。

您还应该设置一个监听器来对当前选定的元素采取操作。

let x;
let y;
let xMax = 2;
let yMax = 2;

document.getElementById('tagList').addEventListener('keyup', function(event) {
  if (!x) {
    x = 0;
  }
  if (!y) {
    y = 0;
  }
  const previousTarget = document.querySelector(`[data-coordinates="${y},${x}"]`);
  previousTarget.classList.remove('selected');

  switch (event.key) {
    case "ArrowDown":
      y++;
      break;
    case "ArrowUp":
      y--;
      break;
    case "ArrowRight":
      x++;
      break;
    case "ArrowLeft":
      x--;
      break;
  }
  if (x > xMax) {
    x = 0;
  }
  if (y > yMax) {
    y = 0;
  }
  if (x < 0) {
    x = xMax;
  }
  if (y < 0) {
    y = yMax;
  }
  const target = document.querySelector(`[data-coordinates="${y},${x}"]`);
  target.classList.add('selected');
});


document.addEventListener('click', function(event) {
  const ul = document.getElementById("tagList");
  const input = document.getElementById('search');

  if (!ul.contains(event.target) && event.target !== input) {
    ul.style.visibility = "hidden"
    input.style = "border-radius: 1px"
    input.style = "padding: 5px";
    enterBtn.style.display = "none"
  }
});

function searchMenu() {
  let input, filter, ul, li, a, i, txtValue;
  input = document.getElementById('search');
  filter = input.value.toUpperCase();
  ul = document.getElementById("tagList");
  li = ul.getElementsByTagName('li');
  enterBtn = document.getElementById('enterButton');

  // Check if there are no matching list items
  let noMatches = true;
  for (i = 0; i < li.length; i++) {
    a = li[i].getElementsByTagName("a")[0];
    txtValue = a.textContent || a.innerText;
    if (txtValue.toUpperCase().indexOf(filter) > -1) {
      li[i].style.display = "block"
      enterBtn.style.display = "none"
      noMatches = false; // When no match found, enable button
    } else {
      enterBtn.style = "background-color: #000000; color: #ffffff";
      enterBtn.style.display = "block"
      li[i].style.display = "none";
    }
  }

  // Show the itemwindow only if there are matches and disable advanced search to prevent the system from unnecessary datafetch from db
  if (!noMatches) {
    ul.style.visibility = "visible"
    input.style = "border: 3px solid #000000"
    input.style.margin = "0",
      enterBtn.style = "background-color: #f2f2f2; color: #ffffff; border: none; box-shadow: none;";
    enterBtn.disabled = true;
    enterBtn.style.display = "block";
    enterBtn.style.cursor = "default";
  } else {
    enterBtn.disabled = false;
    ul.style.visibility = "hidden"
    input.style = "border: 2pxsolid #000000";
    // Hide the taglist if no matches
  }
}

// Call searchMenu func initially to hide the taglist if there are no items to list
searchMenu();

// Click event listener to the search input to show the ul when clicked
const searchInput = document.getElementById('search');
searchInput.addEventListener('click', function(event) {;
  event.stopPropagation(); // Prevent the click event from reaching the doc click listener
  searchMenu(); // Call the searchMenu func again when the input is clicked
});
#smContainer {
  display: flex;
}

#searchBox {
  display: flex;
  justify-content: end;
  max-height: 100px;
  width: 400px;
}

#search {
  padding: 5px;
  outline: none;
  width: inherit;
  max-width: inherit;
}

#enterButton {
  position: absolute;
  border: 0.2rem solid #000000;
  background-color: #f2f2f2;
  color: rgb(0, 0, 0);
  display: none;
  cursor: pointer;
}

#tagList {
  margin: 30px auto;
  position: absolute;
  list-style-type: none;
  border: 1px solid #000000;
  background-color: white;
  visibility: hidden;
  display: grid;
  grid-template-columns: auto auto auto;
  flex-wrap: wrap;
  width: 400px;
}

#tagList li a {
  padding: 2px 2px;
  text-decoration: none;
  color: #000000;
  display: block;
  border: 1px solid #000000;
  margin: 2px;
}

#tagList li a:is(:hover, .selected) {
  background-color: #000000;
  color: #ffffff;
}
<div id="smContainer">
  <div id="searchBox">
    <input type="text" id="search" autocomplete="off" onclick="searchMenu()" onkeyup="searchMenu()" placeholder="filterbox" />
    <button type="submit" id="enterButton">SEARCH</button>
    <ul id="tagList">

      <li><a data-coordinates="0,0" href="#">Ipsum</a></li>
      <li><a data-coordinates="0,1" href="#">Dolor</a></li>
      <li><a data-coordinates="0,2" href="#">Sit</a></li>
      <li><a data-coordinates="1,0" href="#">Amet</a></li>
      <li><a data-coordinates="1,1" href="#">Amet</a></li>
      <li><a data-coordinates="1,2" href="#">Dolor</a></li>
      <li><a data-coordinates="2,0" href="#">Sit</a></li>
      <li><a data-coordinates="2,1" href="#">Amet</a></li>
      <li><a data-coordinates="2,2" href="#">Ipsum</a></li>
    </ul>
  </div>
</div>

© www.soinside.com 2019 - 2024. All rights reserved.