多级标签页需分层管理:一级用data-tab-group="main"、二级用data-tab-group="settings",父子状态隔离,避免display:none导致子组件销毁,改用visibility:hidden+aria-hidden,并确保焦点链连续。

多级标签页不是简单套娃,而是父子关系嵌套:外层切换决定“模块”,内层切换控制“子功能”。直接用同一套 display 逻辑递归处理会失控,必须分层绑定、独立状态管理。
用 data-scope 区分层级作用域
一级标签和二级标签不能共用 data-tab,否则 JS 无法判断当前点击属于哪一层。必须加作用域标识,比如一级用 data-tab-group="main",二级用 data-tab-group="settings"。
- 每个标签按钮带两个关键属性:
data-tab-group(标识所属层级)和data-tab(标识自身 ID) - 对应内容面板也需匹配:
data-tab-group="main" data-tab="profile" - JS 初始化时按
data-tab-group分组获取按钮和面板,避免跨层误操作 - 不推荐用 class 名(如
.tab-main)代替data-tab-group,因为 class 更倾向样式职责,且易被 CSS 框架污染
切换逻辑必须隔离:父级不影响子级状态
点击「设置」标签后展开设置面板,里面还有「账号」「安全」「通知」三个子标签——此时切换子标签,不能重置「设置」本身的激活态,否则用户会丢失上下文。
- 父级切换只控制自己组下的所有面板显隐,不 touch 其他
data-tab-group下的元素 - 子级切换前,先确保其父级面板已显示(可用
closest()向上查,或初始化时建立父子映射) - 不要在子级事件里调用全局“隐藏所有面板”逻辑,那会把父级也干掉
- 默认激活态要分层设置:一级默认激活
data-tab="dashboard",二级在「设置」面板内默认激活data-tab="account"
避免 display: none 导致子级组件销毁
如果二级标签页里有 <input>、<video> 或第三方图表库实例,用 display: none 隐藏整个父面板会导致它们被浏览器卸载,再次展开时输入框失焦、视频重载、图表白屏。
立即学习“前端免费学习笔记(深入)”;
- 对含交互/媒体的子级容器,改用
visibility: hidden+position: absolute占位,同时加aria-hidden="true" - 必须同步更新
tabindex:隐藏时设为-1,显示时恢复为0,否则键盘用户卡在不可见区域 - 若子级使用了 Vue/React,别用
v-if或{show && <Panel>}控制显隐,该用v-show或className切换 - 首次加载时,只展开一级默认项;二级默认项等父面板
offsetParent !== null后再初始化,防止 DOM 未就绪
最常被忽略的是父子焦点链断裂——用户按 Tab 键从一级标签跳进二级区域时,若二级没正确设 tabindex="0" 或 aria-labelledby 指向父标签,就会跳过整个子级。这不是视觉问题,是可访问性硬伤。



















