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
相关产品推荐
相关产品推荐

