You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flexbox下拉列表四向箭头导航功能实现求助

解决方案

核心逻辑

你的列表是Flex多行布局,要实现四向导航,关键是先算出每行能容纳的列表项数量,再根据箭头方向计算下一个要聚焦的项的索引。同时要处理无匹配项时的焦点回退逻辑。

完整代码实现

HTML(适配你的结构)

<div class="filter-container">
  <input type="text" class="search-input" placeholder="搜索..." />
  <button class="search-btn">搜索</button>
  <ul class="dropdown-list">
    <!-- 动态生成的列表项,嵌套跳转链接 -->
    <li><a href="/item1">项目1</a></li>
    <li><a href="/item2">项目2</a></li>
    <li><a href="/item3">项目3</a></li>
    <li><a href="/item4">项目4</a></li>
    <li><a href="/item5">项目5</a></li>
    <li><a href="/item6">项目6</a></li>
  </ul>
</div>

CSS(保留你的Flex多行布局)

.dropdown-list {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  padding: 0;
  margin: 0;
  max-width: 400px; /* 可根据需求调整容器宽度 */
}

.dropdown-list li {
  flex: 0 0 calc(33.33% - 10px); /* 示例每行3个项,间距10px,按需修改 */
  margin: 5px;
}

.dropdown-list a {
  display: block;
  padding: 8px;
  text-decoration: none;
  color: #333;
  border: 1px solid #ddd;
  border-radius: 4px;
}

.dropdown-list a:focus {
  outline: 2px solid #007bff;
  background-color: #f0f8ff;
}

JavaScript(四向导航核心逻辑)

const searchBtn = document.querySelector('.search-btn');
const dropdownList = document.querySelector('.dropdown-list');
const searchInput = document.querySelector('.search-input');

// 全局监听键盘事件
document.addEventListener('keydown', (e) => {
  const activeElement = document.activeElement;
  const listItems = Array.from(dropdownList.querySelectorAll('a'));
  const hasItems = listItems.length > 0;

  // 无匹配项时,强制把焦点切回搜索按钮
  if (!hasItems && activeElement.closest('.dropdown-list')) {
    searchBtn.focus();
    return;
  }

  // 只处理聚焦在列表项或搜索按钮时的操作
  if (!listItems.includes(activeElement) && activeElement !== searchBtn) return;

  // 阻止默认行为,避免页面滚动干扰
  if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Enter'].includes(e.key)) {
    e.preventDefault();
  }

  const currentIndex = listItems.indexOf(activeElement);
  // 计算每行项数:容器宽度除以单个项宽度,取整适配换行
  const itemWidth = listItems[0]?.offsetWidth || 0;
  const containerWidth = dropdownList.offsetWidth;
  const itemsPerRow = itemWidth > 0 ? Math.floor(containerWidth / itemWidth) : 1;

  switch (e.key) {
    case 'ArrowRight':
      if (currentIndex < listItems.length - 1) {
        listItems[currentIndex + 1].focus();
      }
      break;
    case 'ArrowLeft':
      if (currentIndex > 0) {
        listItems[currentIndex - 1].focus();
      }
      break;
    case 'ArrowDown':
      const nextRowIndex = currentIndex + itemsPerRow;
      if (nextRowIndex < listItems.length) {
        listItems[nextRowIndex].focus();
      }
      break;
    case 'ArrowUp':
      const prevRowIndex = currentIndex - itemsPerRow;
      if (prevRowIndex >= 0) {
        listItems[prevRowIndex].focus();
      }
      break;
    case 'Enter':
      if (activeElement.tagName === 'A') {
        activeElement.click(); // 触发链接跳转
      } else if (activeElement === searchBtn) {
        searchInput.focus(); // 搜索按钮回车时切回输入框,可自定义搜索逻辑
      }
      break;
  }
});

// 搜索按钮激活时,按箭头键直接切回搜索输入框(可选)
searchBtn.addEventListener('keydown', (e) => {
  if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {
    e.preventDefault();
    searchInput.focus();
  }
});

关键细节说明

  • 自适应每行项数:通过容器宽度除以单个项宽度取整,适配不同屏幕下的Flex换行情况
  • 焦点边界控制:所有箭头键都做了边界判断,不会超出列表项范围
  • 无匹配项处理:列表为空时,任何聚焦在列表区域的操作都会自动切回搜索按钮
  • 回车事件区分:列表项回车触发跳转,搜索按钮回车可自定义搜索逻辑

内容的提问来源于stack exchange,提问作者prixr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 07:46:24