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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 00:35:27