Skip to content

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>

注意事项

  1. 标签项的 data-tab 属性必须与对应面板的 data-tab 属性一致
  2. 默认显示的面板不需要设置 display: none,其他面板需要隐藏
  3. 激活的标签项需要添加 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 组件中...
            
          

Released under the MIT License.