react固定容器标签超出n+展示
思路:
容器宽度监听
需要知道当前容器的宽度。
可以用
ResizeObserver
来实时监听容器大小变化。
计算可展示的标签数量
遍历标签,测量每个
Tag
占的宽度(包括 margin/padding)。累计标签宽度,直到超出容器最大宽度。
一旦超出,就停止,记录下来能展示的数量。
预留空间给
+n
标签因为可能会有超出的情况,需要给
+n
预留宽度(比如 40px 左右)。
渲染逻辑
如果标签总数 ≤ 可展示数量 → 全部渲染。
如果标签总数 > 可展示数量 → 渲染前 N 个,剩余的合并为
+n
。+n
上可以挂载Tooltip
或Popover
,用于展示完整的隐藏标签。
关键点:
如何测量单个标签的宽度?
常见做法是临时创建一个隐藏的 DOM 元素,把标签内容放进去测量clientWidth
。
也可以直接渲染在页面中,用getBoundingClientRect()
获取。如何保证响应式?
ResizeObserver
会在容器大小变化时重新计算,不需要手动监听window.onresize
。性能优化
标签数如果很多,可以提前缓存测量结果。
只在标签数据或容器宽度变化时重新计算。
初始化 → 监听容器宽度 → 计算可展示数量↓遍历标签 → 累计宽度 → 超出则停止↓渲染:前 N 个标签 + (超出的 +n 标签)
代码:
import React, { useRef, useState, useEffect } from "react";
import { Tag, Tooltip } from "antd";// 标签列表组件
const TagList = ({ data = [] }) => {const containerRef = useRef(null);const [visibleCount, setVisibleCount] = useState(data.length);useEffect(() => {if (!containerRef.current) return;const resizeObserver = new ResizeObserver(() => {calcVisibleCount();});resizeObserver.observe(containerRef.current);return () => {resizeObserver.disconnect();};}, [data]);const calcVisibleCount = () => {const container = containerRef.current;if (!container) return;const containerWidth = container.clientWidth;let total = 0;let count = data.length;// 临时创建元素测量宽度const temp = document.createElement("div");temp.style.position = "absolute";temp.style.visibility = "hidden";temp.style.whiteSpace = "nowrap";document.body.appendChild(temp);for (let i = 0; i < data.length; i++) {temp.innerHTML = `<span class="ant-tag">${data[i]}</span>`;const w = temp.clientWidth + 8; // 8px = margin-right 近似if (total + w > containerWidth - 40) {// 40 给 +N 预留宽度count = i;break;}total += w;}document.body.removeChild(temp);setVisibleCount(count);};const showTags = data.slice(0, visibleCount);const hiddenTags = data.slice(visibleCount);return (<divref={containerRef}style={{ width: "100%", overflow: "hidden", whiteSpace: "nowrap" }}>{showTags.map((item, index) => (<Tag key={index}>{item}</Tag>))}{hiddenTags.length > 0 && (<Tooltiptitle={<div style={{ display: "flex", flexWrap: "wrap", gap: 4 }}>{hiddenTags.map((item, idx) => (<Tag key={idx}>{item}</Tag>))}</div>}><Tag>+{hiddenTags.length}</Tag></Tooltip>)}</div>);
};export default TagList;
使用:
<divstyle={{width: 300,maxWidth: 300,}}><TagList data={tags} /></div>