标签页

渲染一个带有标签菜单和视图的组件。

  • 定义一个 Tabs 组件。使用 useState() 钩子将 bindIndex 状态变量的初始值设为 defaultIndex
  • 定义一个 TabItem 组件,并通过识别函数的名称,过滤传递给 Tabs 组件的 children,以删除不必要的节点,只保留 TabItem
  • 定义 changeTab 函数,当点击菜单中的 <button> 时执行。
  • changeTab 函数执行传递的回调函数 onTabClick,并根据点击的元素更新 bindIndex
  • 使用 Array.prototype.map() 在收集到的节点上渲染标签菜单和视图。
  • 使用 bindIndex 的值来确定活动标签,并应用正确的 className
.tab-menu > button {
  cursor: pointer;
  padding: 8px 16px;
  border: 0;
  border-bottom: 2px solid transparent;
  background: none;
}

.tab-menu > button.focus {
  border-bottom: 2px solid #007bef;
}

.tab-menu > button:hover {
  border-bottom: 2px solid #007bef;
}

.tab-content {
  display: none;
}

.tab-content.selected {
  display: block;
}
const TabItem = props => <div {...props} />;

const Tabs = ({ defaultIndex = 0, onTabClick, children }) => {
  const [bindIndex, setBindIndex] = React.useState(defaultIndex);
  const changeTab = newIndex => {
    if (typeof onTabClick === 'function') onTabClick(newIndex);
    setBindIndex(newIndex);
  };
  const items = children.filter(item => item.type.name === 'TabItem');

返回 (
  <div className="wrapper">
    <div className="tab-menu">
      {items.map(({ props: { index, label } }) => (
        <button
          key={`tab-btn-${index}`}
          onClick={() => changeTab(index)}
          className={bindIndex === index ? 'focus' : ''}
        >
          {label}
        </button>
      ))}
    </div>
    <div className="tab-view">
      {items.map(({ props }) => (
        <div
          {...props}
          className={`tab-content ${
            bindIndex === props.index ? 'selected' : ''
          }`}
          key={`tab-content-${props.index}`}
        />
      ))}
    </div>
  </div>
);

ReactDOM.createRoot(document.getElementById('root')).render(
  <Tabs defaultIndex="1" onTabClick={console.log}>
    <TabItem label="A" index="1">
      Lorem ipsum
    </TabItem>
    <TabItem label="B" index="2">
      Dolor sit amet
    </TabItem>
  </Tabs>
);