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

JavaScript自动完成组件键盘导航中scrollIntoView底部滚动异常问题

Autocomplete组件键盘导航滚动异常修复

问题根源

你的实现存在两个核心问题:

  • 滚动位置计算逻辑错误,导致向下滚动时无法正确定位高亮项到列表底部
  • 状态更新是异步的,直接在按键事件中调用滚动函数会使用旧的highlightedIndex值

修复方案

1. 修正滚动计算函数

替换原scrollOptionIntoView函数,使用正确的位置计算逻辑:

const scrollOptionIntoView = () => {
  if (listRef.current && highlightedIndex >= 0) {
    const optionElement = listRef.current.children[highlightedIndex] as HTMLElement;
    if (!optionElement) return;

    const listContainer = listRef.current;
    const optionTop = optionElement.offsetTop;
    const optionBottom = optionTop + optionElement.offsetHeight;
    const viewportTop = listContainer.scrollTop;
    const viewportBottom = viewportTop + listContainer.clientHeight;

    // 向上滚动:高亮项顶部超出视口时,滚动到视口顶部对齐
    if (optionTop < viewportTop) {
      listContainer.scrollTop = optionTop;
    } 
    // 向下滚动:高亮项底部超出视口时,滚动到视口底部对齐
    else if (optionBottom > viewportBottom) {
      listContainer.scrollTop = optionBottom - listContainer.clientHeight;
    }
  }
};

2. 解决异步状态更新问题

移除按键事件中直接调用scrollOptionIntoView的代码,改用useEffect监听highlightedIndex变化后执行滚动:

修改handleKeyDown:

const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
  if (event.key === "ArrowUp") {
    event.preventDefault();
    setHighlightedIndex((prevIndex) => (prevIndex > 0 ? prevIndex - 1 : prevIndex));
  } else if (event.key === "ArrowDown") {
    event.preventDefault();
    setHighlightedIndex((prevIndex) =>
      prevIndex < options.length - 1 ? prevIndex + 1 : prevIndex
    );
  } else if (
    event.key === "Enter" &&
    highlightedIndex >= 0 &&
    highlightedIndex < options.length
  ) {
    event.preventDefault();
    setInputValue(options[highlightedIndex]);
    setHighlightedIndex(-1);
  }
};

添加useEffect监听:

import { useEffect } from 'react';

// ... 其他组件代码

useEffect(() => {
  // 仅在下拉框展开且有高亮项时执行滚动
  if (open && highlightedIndex >= 0) {
    scrollOptionIntoView();
  }
}, [highlightedIndex, open]);

修复说明

  • 滚动逻辑修正:原代码中错误地在optionBottom计算中加入了scrollTop,导致底部位置计算失真;同时optionTop的偏移计算不符合顶部对齐需求,修正后直接基于元素自身的offsetTop和offsetHeight与视口边界对比,确保滚动行为精准。
  • 异步状态处理:React的setState是异步操作,按键事件中直接调用滚动函数会读取到未更新的highlightedIndex,通过useEffect监听状态变化,确保滚动操作始终基于最新的高亮项索引执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:25:41