使用React hook封装一个Tab切换的函数式组件

5,479 阅读1分钟

背景

  • 使用antd UI框架的Tabs组件,需要根据设计图对原生样式再次修改,步骤繁琐。
  • Tabs标签内,需要再配置TabPane标签和每页内容,至少十几行才能完成。
// 使用antd
<Tabs defaultActiveKey="1" onChange={callback}>
    <TabPane tab="城市概况" key="1">
        <Outline />
    </TabPane>
    <TabPane tab="城市历史" key="2">
        <History />
    </TabPane>
    <TabPane tab="地理位置" key="3">
        <Geo />
    </TabPane>
</Tabs>

本文使用react hook,将tab所有相关的操作都进行封装,只留下一个tabSet配置接口。 仅仅使用一行代码即可在页面显示Tab组件。

使用如下

<Tab tabSet={tabSet} />

tabSet的格式如下

const tabSet = {
  '城市概况': <Outline />,
  '城市历史': <History />,
  '地理位置': <Geo />,
}

其中,tabSet的属性名是tab的标签名;
值是tab每个标签页要显示的内容,以组件形式引入。

Tab组件的实现

完整代码

function Tab(props) {
  const { tabSet } = props 
  const arr = Object.keys(tabSet) // 由tab标签名组成的数组
  const [selected, setSelected] = useState(arr[0]) // 当前选中的tab标签
  
  function select(item) {
    setSelected(item)
  }
  return (
        <div>
            <div className={styles.selectWrapper}>
                {arr.map(item => (
                    <div
                        key={item}
                        className={item === selected ? styles.selectItem_active : styles.selectItem_basic}
                        onClick={() => select(item)}
                    >
                        {item}
                    </div>
                ))}
            </div>
            {tabSet[selected]} // 当前标签页的展示内容
        </div>
  )
}

函数组件内使用useState Hook,通过selected变量来存放选中的标签名;
样式可灵活自行配置。

样式

记录一下简单的配置,使用的是语法是less

.selectWrapper{
    display: flex;
    height: 50px;
    background: #F4F5F7;
    font-size: 16px;
    font-family: PingFangSC-Medium, PingFang SC;
    font-weight: 500;
    div{
        height: 100%;
        padding: 0 40px;
        line-height: 50px;
        cursor: pointer;
    }
}
.selectItem_active{
    color: #FFFFFF;
    background: #2D8CF6;
}

效果图

1.png

拓展: 不传入Tab页内容,使用a标签定位

情景

多个标签页共享使用同一个组件,或者tab标签名由后端传过来。

使用


const arr = ['城市概况', '城市历史', '地理位置']

function getSelect(item) { console.log(item) }

<Tab onChange={getSelect} arr={arr} />

<div id="城市概况"></div>

组件

import React, { useState } from 'react';
import styles from './component.less';

export default props => {
  const { onChange, arr } = props;
  const [selected, setSelected] = useState(arr[0]); // 当前选中的tab标签

  function select(item) {
    setSelected(item);
    onChange(item)
  }
  return (
    <div className={styles.selectWrapper}>
      {Array.isArray(arr) &&
        arr.map(item => (
          <a
            href={`#${item}`}
            className={item === selected ? styles.selectItem_active : styles.selectItem_basic}
            onClick={() => select(item)}
          >
            {item}
          </a>
        ))}
    </div>
  );
};