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

React.js固定宽度容器如何优先展示超出范围的选中列表项

实现方案

核心逻辑调整

你原来的逻辑是从左到右依次塞入元素,导致靠后的选中项被隐藏。调整可见元素计算规则即可实现需求,优先级顺序为:

  • 第一优先级展示选中项,先扣除选中项的宽度
  • 剩余空间优先从选中项左侧的相邻元素开始,从右往左依次添加,直到空间不足
  • 还有剩余空间的话,再从选中项右侧的相邻元素开始,从左往右依次添加,直到空间不足

完整修改代码

import "./styles.css";
import React, { createRef, useMemo, useRef } from "react";
const data = [
  { title: "xahsdh" },
  { title: "hello" },
  { title: "hessllo" },
  { title: "hesslsssloasdasdasdasdasdsa" },
  { title: "navveiii" }
];
// 可修改选中项索引测试效果
const selectedItem = 3;
export default function App() {
  const elRefs = useMemo(
    () => Array.from({ length: data.length }).map(() => createRef()),
    []
  );
  const [state, setState] = React.useState({
    containerWidth: 0,
    itemWidthMap: {}
  });
  const [isCalculated, setIsCalculated] = React.useState(false);
  const containerRef = useRef(null);

  React.useEffect(() => {
    calculateDimension();
  }, []);

  const calculateDimension = () => {
    const containerWidth = containerRef.current.offsetWidth;
    const itemWidthMap = {};
    elRefs.forEach((ref, index) => {
      itemWidthMap[index] = ref.current?.offsetWidth || 0;
    });
    setState({
      containerWidth,
      itemWidthMap
    });
    setIsCalculated(true);
  };

  const getVisibleItems = () => {
    const { containerWidth, itemWidthMap } = state;
    if (!isCalculated) return { visible: [], hidden: [] };

    const selectedWidth = itemWidthMap[selectedItem];
    let remainingWidth = containerWidth - selectedWidth;
    // 可见列表初始只有选中项,存原始索引
    const visibleIndex = [selectedItem];
    // 先加选中项左边的元素,从近到远
    let leftPointer = selectedItem - 1;
    while (leftPointer >= 0 && remainingWidth > 0) {
      const currentWidth = itemWidthMap[leftPointer];
      if (remainingWidth - currentWidth >= 0) {
        visibleIndex.unshift(leftPointer);
        remainingWidth -= currentWidth;
        leftPointer--;
      } else {
        break;
      }
    }
    // 再加选中项右边的元素,从近到远
    let rightPointer = selectedItem + 1;
    while (rightPointer < data.length && remainingWidth > 0) {
      const currentWidth = itemWidthMap[rightPointer];
      if (remainingWidth - currentWidth >= 0) {
        visibleIndex.push(rightPointer);
        remainingWidth -= currentWidth;
        rightPointer++;
      } else {
        break;
      }
    }
    // 生成可见和隐藏列表
    const visible = visibleIndex.map(idx => data[idx]);
    const hidden = data.filter((_, idx) => !visibleIndex.includes(idx));
    return { visible, visibleIndex, hidden };
  };

  const { visible, visibleIndex = [], hidden = [] } = getVisibleItems();

  return (
    <div className="container" ref={containerRef}>
      {/* 预计算元素宽度的隐藏层 */}
      <ul id="dummy">
        {data.map((el, i) => (
          <li
            ref={elRefs[i]}
            key={i}
          >
            {el.title}
          </li>
        ))}
      </ul>
      {/* 可见列表 */}
      <ul id="visible">
        {visible.map((el, i) => (
          <li 
            className={visibleIndex[i] === selectedItem ? "selected" : ""} 
            key={visibleIndex[i]}
          >
            {el.title}
          </li>
        ))}
      </ul>
      {/* 隐藏列表 */}
      <ul id="hidden">
        {hidden.map((el, i) => (
          <li className="hide" key={i}>
            {el.title}
          </li>
        ))}
      </ul>
    </div>
  );
}

配套样式(styles.css)

.container {
  width: 200px;
}
ul {
  display: flex;
  list-style: none;
  padding: 0;
  margin: 0;
  gap: 8px;
}
li {
  white-space: nowrap;
  padding: 2px 4px;
  /* 选中项宽度超过容器时自动截断 */
  overflow: hidden;
  text-overflow: ellipsis;
}
.selected {
  border: 1px solid blue;
}
.hide {
  display: none;
}
/* 预计算层不占可视空间 */
#dummy {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 06:12:00