近期在学习React的源码,其中讲到有关于React的一些api内部的实现。看到了React.Children,觉得不错,于是手动使用它来实现一个简单的Tabs组件,废话不多说直接开撸。
- 入口文件 UseTab.jsx
import React from 'react'
import {Tabs, TabPlane} from '../myTab'
const UseTab = () => {
return <>
<Tabs activeIndex={1} onChange={(e) => {console.log(e,'ee')}}>
<TabPlane key={1} name="tab1">选项卡一的内容</TabPlane>
<TabPlane key={2} name="tab2">选项卡二的内容</TabPlane>
<TabPlane key={3} name="tab3">选项卡三的内容</TabPlane>
</Tabs>
</>
}
export default UseTab
- 自定义的内部组件Tabs
import React, { useEffect, useState } from 'react'
import './index.css'
/**
* 实现效果:选项卡切换
* 1. 使用React.chilren方法
* 2. 测试能不能使用简单的数组 map 方法
*/
const TabPlane = ({children}) => {
return <div>
{children}
</div>
}
const Tabs = ({children, activeIndex, onChange}) => {
const [currentIndex, setCurrentIndex] = useState(1)
useEffect(() => {
if (activeIndex) {
setCurrentIndex(activeIndex)
}
}, [activeIndex])
const tabClick = (key) => {
if (key === currentIndex) {
return
}
setCurrentIndex(key)
onChange(key)
}
return <div className="card">
<div className="topclick">
{React.Children.map(children, (element, index)=>{
console.log(element, 'element')
const { name } = element.props
return <div style={{color: currentIndex == element.key ? '#7893f7' : ''}} onClick={() => tabClick(element.key)}>{name}</div>
})}
</div>
<div className="tabContainer">
{React.Children.map(children, (element, index)=>{
const { children } = element.props
return <div className={currentIndex == element.key ? 'block' : 'none'}>{children}</div>
})}
</div>
</div>
}
export { Tabs, TabPlane }
- style.css
.card{
background-color: #f6f6f6;
font-size: 12px;
color: #000;
width: 400px;
height: 200px;
border-radius: 4px;
border: 2px solid #ececee;
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
}
.topclick{
display: flex;
justify-content: flex-start;
align-items: center;
border-bottom: 1px solid #ececee;
}
.topclick > div{
width: 80px;
height: 30px;
line-height: 30px;
text-align: center;
cursor: pointer;
}
.tabContainer{
flex-grow: 1;
}
.block{
display: block;
padding: 10px 20px;
}
.none{
display: none;
}