React实现:每个子菜单组超过3项时隐藏多余元素
React子菜单数量统计与超出隐藏实现
你的当前代码存在两个核心问题:一是单个ElementRef只能统计最外层.menus的子节点数量(即2个.submenus容器),无法单独统计每个子菜单组的子项数量;二是直接操作DOM的方式不符合React数据流理念,更推荐用数据驱动逻辑。
以下是两种可行的实现方案:
1. 数据驱动实现(推荐)
先定义结构化的菜单数据,通过遍历数据渲染菜单,同时直接在数据层面控制显示逻辑:
import { useState } from 'react'; export default function App() { // 定义菜单数据源,每个子组包含名称和子项列表 const menuData = [ { groupName: "子菜单组1", items: ["Menu 1", "Menu 2", "Menu 3", "Menu 4", "Menu 5"] }, { groupName: "子菜单组2", items: ["Menu 1", "Menu 2", "Menu 3", "Menu 4"] } ]; // 记录展开的子组索引,用于控制展开/收起 const [expandedGroups, setExpandedGroups] = useState([]); // 切换子组展开状态 const toggleExpand = (groupIndex) => { setExpandedGroups(prev => prev.includes(groupIndex) ? prev.filter(idx => idx !== groupIndex) : [...prev, groupIndex] ); }; return ( <div className="menus"> {menuData.map((group, groupIndex) => { const isExpanded = expandedGroups.includes(groupIndex); // 确定显示的子项:展开则显示全部,否则只显示前3个 const displayItems = isExpanded ? group.items : group.items.slice(0, 3); return ( <div className="submenus" key={groupIndex}> {displayItems.map((item, idx) => ( <div key={idx}>{item}</div> ))} {/* 子项超过3个时,显示展开/收起按钮 */} {group.items.length > 3 && ( <button onClick={() => toggleExpand(groupIndex)}> {isExpanded ? "收起" : `查看更多(${group.items.length - 3})`} </button> )} </div> ); })} </div> ); }
2. DOM操作实现(仅适用于特殊场景)
如果必须通过操作DOM实现,需给每个.submenus单独设置ref,逐个统计并处理子项:
import { useRef, useEffect } from 'react'; export default function App() { // 创建ref数组,对应每个子菜单组 const subMenuRefs = useRef([]); useEffect(() => { subMenuRefs.current.forEach(ref => { if (ref) { // 过滤文本节点,统计实际子项元素数量 const validItems = Array.from(ref.childNodes).filter(node => node.nodeType === 1); const itemCount = validItems.length; console.log(`子菜单组子项数量:${itemCount}`); // 隐藏第3个之后的子项 if (itemCount > 3) { validItems.slice(3).forEach(item => { item.style.display = 'none'; }); } } }); }, []); return ( <div className="menus"> <div className="submenus" ref={el => subMenuRefs.current[0] = el}> <div>Menu 1</div> <div>Menu 2</div> <div>Menu 3</div> <div>Menu 4</div> <div>Menu 5</div> </div> <div className="submenus" ref={el => subMenuRefs.current[1] = el}> <div>Menu 1</div> <div>Menu 2</div> <div>Menu 3</div> <div>Menu 4</div> </div> </div> ) }
方案对比
- 数据驱动:完全符合React设计理念,逻辑清晰易维护,还能轻松扩展展开/收起等交互功能。
- DOM操作:仅适用于无法通过数据驱动的特殊场景,缺点是与DOM结构强耦合,后续修改DOM易导致逻辑失效。
内容的提问来源于stack exchange,提问作者Vidya Tyagi
相关产品推荐
相关产品推荐

