我有一个过滤器下拉列表,其中有一个搜索按钮,如果列表中没有项目,按钮就会激活 但是下拉列表中有多个项目在一行中,所以 我想要的是能够使用箭头键以各种方式在它们之间导航,并在按下 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>
这是部分解决方案。它的工作原理是更新内部坐标 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>