Tabs 标签页
标签页组件,用于内容切换展示。
基础用法
html
<div class="sa-tabs" id="demo-tabs">
<div class="sa-tabs__header">
<div class="sa-tabs__item sa-tabs__item--active" data-tab="tab1">标签一</div>
<div class="sa-tabs__item" data-tab="tab2">标签二</div>
<div class="sa-tabs__item" data-tab="tab3">标签三</div>
</div>
<div class="sa-tabs__content">
<div class="sa-tabs__panel" data-tab="tab1">
内容一
</div>
<div class="sa-tabs__panel" data-tab="tab2" style="display: none;">
内容二
</div>
<div class="sa-tabs__panel" data-tab="tab3" style="display: none;">
内容三
</div>
</div>
</div>
<script>
// 标签页切换
const tabItems = document.querySelectorAll('#demo-tabs .sa-tabs__item');
const tabPanels = document.querySelectorAll('#demo-tabs .sa-tabs__panel');
tabItems.forEach(item => {
item.addEventListener('click', () => {
const tabName = item.getAttribute('data-tab');
// 切换标签
tabItems.forEach(i => i.classList.remove('sa-tabs__item--active'));
item.classList.add('sa-tabs__item--active');
// 切换面板
tabPanels.forEach(p => p.style.display = 'none');
document.querySelector(`.sa-tabs__panel[data-tab="${tabName}"]`).style.display = 'block';
});
});
</script>加载 SanoUI 组件中...
不同位置
通过 CSS 类控制标签页位置。
html
<!-- 顶部(默认) -->
<div class="sa-tabs">
<!-- ... -->
</div>
<!-- 底部 -->
<div class="sa-tabs sa-tabs--bottom">
<!-- ... -->
</div>
<!-- 左侧 -->
<div class="sa-tabs sa-tabs--left">
<!-- ... -->
</div>
<!-- 右侧 -->
<div class="sa-tabs sa-tabs--right">
<!-- ... -->
</div>可关闭的标签页
通过添加关闭按钮实现可关闭功能。
html
<div class="sa-tabs" id="demo-tabs-closable">
<div class="sa-tabs__header">
<div class="sa-tabs__item sa-tabs__item--active" data-tab="tab1">
<span>标签一</span>
<button class="sa-tabs__close" onclick="closeTab('tab1')">×</button>
</div>
<div class="sa-tabs__item" data-tab="tab2">
<span>标签二</span>
<button class="sa-tabs__close" onclick="closeTab('tab2')">×</button>
</div>
</div>
<div class="sa-tabs__content">
<!-- ... -->
</div>
</div>HTML 结构
基本结构
html
<div class="sa-tabs">
<div class="sa-tabs__header">
<div class="sa-tabs__item sa-tabs__item--active" data-tab="tab-name">标签文本</div>
</div>
<div class="sa-tabs__content">
<div class="sa-tabs__panel" data-tab="tab-name">面板内容</div>
</div>
</div>CSS 类说明
| 类名 | 说明 |
|---|---|
sa-tabs | 标签页容器 |
sa-tabs__header | 标签头容器 |
sa-tabs__item | 标签项 |
sa-tabs__item--active | 激活的标签项 |
sa-tabs__content | 内容容器 |
sa-tabs__panel | 面板内容 |
sa-tabs__close | 关闭按钮 |
数据属性
| 属性 | 说明 |
|---|---|
data-tab | 标签页唯一标识,标签项和面板需要对应 |
示例代码
完整示例
html
<div class="sa-tabs" id="my-tabs">
<div class="sa-tabs__header">
<div class="sa-tabs__item sa-tabs__item--active" data-tab="basic">基本信息</div>
<div class="sa-tabs__item" data-tab="detail">详细信息</div>
<div class="sa-tabs__item" data-tab="setting">设置</div>
</div>
<div class="sa-tabs__content">
<div class="sa-tabs__panel" data-tab="basic">
<form>
<input type="text" placeholder="用户名">
</form>
</div>
<div class="sa-tabs__panel" data-tab="detail" style="display: none;">
<p>详细信息内容</p>
</div>
<div class="sa-tabs__panel" data-tab="setting" style="display: none;">
<p>设置内容</p>
</div>
</div>
</div>
<script>
function initTabs(containerId) {
const container = document.getElementById(containerId);
const tabItems = container.querySelectorAll('.sa-tabs__item');
const tabPanels = container.querySelectorAll('.sa-tabs__panel');
tabItems.forEach(item => {
item.addEventListener('click', () => {
const tabName = item.getAttribute('data-tab');
// 切换标签
tabItems.forEach(i => i.classList.remove('sa-tabs__item--active'));
item.classList.add('sa-tabs__item--active');
// 切换面板
tabPanels.forEach(p => p.style.display = 'none');
const activePanel = container.querySelector(`.sa-tabs__panel[data-tab="${tabName}"]`);
if (activePanel) {
activePanel.style.display = 'block';
}
});
});
}
initTabs('my-tabs');
</script>注意事项
- 标签项的
data-tab属性必须与对应面板的data-tab属性一致 - 默认显示的面板不需要设置
display: none,其他面板需要隐藏 - 激活的标签项需要添加
sa-tabs__item--active类
API
HTML 结构
Tabs 组件通过 HTML 结构和 CSS 类实现,无需 JavaScript 类实例化。
CSS 类
| 类名 | 说明 |
|---|---|
sa-tabs | 标签页容器 |
sa-tabs__header | 标签头容器 |
sa-tabs__item | 标签项 |
sa-tabs__item--active | 激活的标签项 |
sa-tabs__content | 内容容器 |
sa-tabs__panel | 面板内容 |
sa-tabs__close | 关闭按钮 |
sa-tabs--bottom | 标签在底部 |
sa-tabs--left | 标签在左侧 |
sa-tabs--right | 标签在右侧 |
Data 属性
| 属性 | 说明 | 类型 |
|---|---|---|
data-tab | 标签页唯一标识(标签项和面板必须对应) | string |
实际使用场景
场景 1:用户信息管理
使用标签页组织用户的不同信息模块。
html
<div class="sa-tabs" id="user-tabs">
<div class="sa-tabs__header">
<div class="sa-tabs__item sa-tabs__item--active" data-tab="basic">基本信息</div>
<div class="sa-tabs__item" data-tab="contact">联系方式</div>
<div class="sa-tabs__item" data-tab="security">安全设置</div>
</div>
<div class="sa-tabs__content">
<div class="sa-tabs__panel" data-tab="basic">
<form class="sa-form" style="max-width: 500px;" data-label-position="right" data-label-width="100px">
<div class="sa-form-item">
<label class="sa-form-item__label">用户名</label>
<div class="sa-form-item__content">
<div class="sa-input" data-placeholder="请输入用户名" style="width: 100%;"></div>
</div>
</div>
<div class="sa-form-item">
<label class="sa-form-item__label">邮箱</label>
<div class="sa-form-item__content">
<div class="sa-input" data-type="email" data-placeholder="请输入邮箱" style="width: 100%;"></div>
</div>
</div>
</form>
</div>
<div class="sa-tabs__panel" data-tab="contact" style="display: none;">
<p>联系方式内容</p>
</div>
<div class="sa-tabs__panel" data-tab="security" style="display: none;">
<p>安全设置内容</p>
</div>
</div>
</div>
<script>
SA.init('body');
function initTabs(containerId) {
const container = document.getElementById(containerId);
const tabItems = container.querySelectorAll('.sa-tabs__item');
const tabPanels = container.querySelectorAll('.sa-tabs__panel');
tabItems.forEach(item => {
item.addEventListener('click', () => {
const tabName = item.getAttribute('data-tab');
tabItems.forEach(i => i.classList.remove('sa-tabs__item--active'));
item.classList.add('sa-tabs__item--active');
tabPanels.forEach(p => p.style.display = 'none');
const activePanel = container.querySelector(`.sa-tabs__panel[data-tab="${tabName}"]`);
if (activePanel) {
activePanel.style.display = 'block';
}
});
});
}
initTabs('user-tabs');
</script>加载 SanoUI 组件中...
场景 2:动态标签页
动态添加和删除标签页。
html
<div class="sa-tabs" id="dynamic-tabs">
<div class="sa-tabs__header" id="tabs-header">
<div class="sa-tabs__item sa-tabs__item--active" data-tab="tab1">标签1</div>
</div>
<div class="sa-tabs__content" id="tabs-content">
<div class="sa-tabs__panel" data-tab="tab1">内容1</div>
</div>
</div>
<div style="margin-top: 1rem;">
<button class="sa-button sa-button--primary" onclick="addTab()">添加标签</button>
<button class="sa-button" onclick="removeTab()">删除当前标签</button>
</div>
<script>
SA.init('body');
let tabCount = 1;
let activeTab = 'tab1';
function initTabs() {
const container = document.getElementById('dynamic-tabs');
const tabItems = container.querySelectorAll('.sa-tabs__item');
const tabPanels = container.querySelectorAll('.sa-tabs__panel');
tabItems.forEach(item => {
item.onclick = () => {
const tabName = item.getAttribute('data-tab');
activeTab = tabName;
tabItems.forEach(i => i.classList.remove('sa-tabs__item--active'));
item.classList.add('sa-tabs__item--active');
tabPanels.forEach(p => p.style.display = 'none');
const panel = container.querySelector(`.sa-tabs__panel[data-tab="${tabName}"]`);
if (panel) panel.style.display = 'block';
};
});
}
function addTab() {
tabCount++;
const tabName = `tab${tabCount}`;
const header = document.getElementById('tabs-header');
const content = document.getElementById('tabs-content');
const newItem = document.createElement('div');
newItem.className = 'sa-tabs__item';
newItem.setAttribute('data-tab', tabName);
newItem.textContent = `标签${tabCount}`;
const newPanel = document.createElement('div');
newPanel.className = 'sa-tabs__panel';
newPanel.setAttribute('data-tab', tabName);
newPanel.style.display = 'none';
newPanel.textContent = `内容${tabCount}`;
header.appendChild(newItem);
content.appendChild(newPanel);
initTabs();
newItem.click();
}
function removeTab() {
const container = document.getElementById('dynamic-tabs');
const activeItem = container.querySelector(`.sa-tabs__item[data-tab="${activeTab}"]`);
const activePanel = container.querySelector(`.sa-tabs__panel[data-tab="${activeTab}"]`);
if (container.querySelectorAll('.sa-tabs__item').length <= 1) {
alert('至少保留一个标签');
return;
}
activeItem.remove();
activePanel.remove();
const firstTab = container.querySelector('.sa-tabs__item');
if (firstTab) {
activeTab = firstTab.getAttribute('data-tab');
firstTab.click();
}
initTabs();
}
initTabs();
</script>加载 SanoUI 组件中...