如何组合组件以在 React 中创建选项卡
介绍
本指南将重点介绍如何组合组件以创建一个选项卡组件,该组件将以声明方式显示基于选项卡的导航视图 - 即使用更少、更简单的 props,且更高级别没有回调。所有逻辑都将位于<Tabs />组件内,因此可以轻松地在项目中的任何位置使用它。
组件
在<App />组件内部,按如下方式调用<Tabs />组件。
export default function App() {
return (
<div className="App">
<h1>Tab Component Demo</h1>
<h2>Start adding tabs to see some magic happen!</h2>
<Tabs>
<div title="Tab 1">
Ut condimentum, ex sit amet rutrum ultrices, nisi velit condimentum
mi, et sagittis turpis ligula ut neque. Nunc ut arcu velit. Sed
suscipit nisl est, ut scelerisque elit pretium et.
</div>
<div title="Tab 2">
Phasellus vel nisi lectus. Curabitur ac efficitur quam. Aliquam
faucibus, nibh non auctor auctor, lectus leo cursus massa, ac ornare
dolor ante eu libero.
</div>
<div title="Tab 3">
Aliquam erat volutpat. Sed id pulvinar magna. Aenean scelerisque ex
vitae faucibus faucibus. Proin rutrum est eget odio faucibus tempor.
Nulla ut tellus non urna congue finibus.
</div>
</Tabs>
</div>
);
}
<Tabs />组件可以有多个子组件来代表每个选项卡。每个选项卡必须有一个title属性,并且应包含选项卡内容作为其子项。
一个简单的组件
让我们对组件的基本结构进行排序。
class Tabs extends Component {
state = {
activeTabIndex: 0
};
render() {
const { activeTabIndex } = this.state;
const activeTab = props.children[activeTabIndex];
return (
<div>
<div className="tabs">
{
//
}
</div>
<div className="tab-content">{activeTab.props.children}</div>
</div>
);
}
}
在该状态下,跟踪活动选项卡索引,以便您可以跟踪哪个选项卡当前处于活动状态。
在tabs部分中,循环遍历子项并在<button />中显示每个标题。单击 tab 按钮时,将索引设置为当前活动选项卡。tab -content部分将显示活动选项卡的内容。
// ...
<div className="tabs">
{props.children.map((tab, i) => (
<button
className="tab-btn"
onClick={() => {
setActiveTabIndex(i);
}}
key={i}
>
{tab.props.title}
</button>
))}
</div>
// ...
现在,如果您查看结果,您将能够浏览选项卡。但看起来不太好;用户无法了解哪个选项卡当前处于活动状态。因此,您必须为此创建一个选项卡指示器。
// ...
<div className="tabs">
{props.children.map((tab, i) => (
<button
className="tab-btn"
onClick={() => {
setActiveTabIndex(i);
}}
key={i}
>
{tab.props.title}
</button>
))}
</div>
<div className="tab-indicator-container">
<div
className="tab-indicator"
style={{
width: 100 / props.children.length + "%",
transform: `translateX(${activeTabIndex * 100}%)`
}}
/>
</div>
<div className="tab-content">{activeTab.props.children}</div>
// ...
使用transform属性将指示器滑动到当前活动的选项卡。要确定指示器的宽度,请考虑选项卡数量,可以使用props.children.length进行检索。
使用此 CSS 来美化组件。
.tabs {
display: flex;
align-items: center;
justify-content: center;
}
.tab-btn {
display: block;
flex: 1;
padding: 8px 20px;
background: #eee;
border: 0;
}
.tab-indicator-container {
display: flex;
background: #eee;
margin-bottom: 10px;
}
.tab-indicator {
height: 3px;
background: #007bff;
transition: transform 0.2s;
}
.tab-content {
padding: 10px;
}
最后,<Tabs />组件将如下所示。
class Tabs extends Component {
state = {
activeTabIndex: 0
};
render() {
const { activeTabIndex } = this.state;
const activeTab = props.children[activeTabIndex];
return (
<div>
<div className="tabs">
{props.children.map((tab, i) => (
<button
className="tab-btn"
onClick={() => {
this.setState({ activeTabIndex: i });
}}
key={i}
>
{tab.props.title}
</button>
))}
</div>
<div className="tab-indicator-container">
<div
className="tab-indicator"
style={{
width: 100 / props.children.length + "%",
transform: `translateX(${activeTabIndex * 100}%)`
}}
/>
</div>
<div className="tab-content">{activeTab.props.children}</div>
</div>
);
}
}
除了类组件,您还可以使用useState钩子来创建函数组件。以下是函数版本的外观。
const Tabs = props => {
const [activeTabIndex, setActiveTabIndex] = useState(0);
const activeTab = props.children[activeTabIndex];
return (
<div>
<div className="tabs">
{props.children.map((tab, i) => (
<button
className="tab-btn"
onClick={() => {
setActiveTabIndex(i);
}}
key={i}
>
{tab.props.title}
</button>
))}
</div>
<div className="tab-indicator-container">
<div
className="tab-indicator"
style={{
width: 100 / props.children.length + "%",
transform: `translateX(${activeTabIndex * 100}%)`
}}
/>
</div>
<div className="tab-content">{activeTab.props.children}</div>
</div>
);
};
这是最终的输出。
完整源代码
这是完整的源代码,供您参考。
App.js
import React, { useState } from "react";
import "./styles.css";
const Tabs = props => {
const [activeTabIndex, setActiveTabIndex] = useState(0);
const activeTab = props.children[activeTabIndex];
return (
<div>
<div className="tabs">
{props.children.map((tab, i) => (
<button
className="tab-btn"
onClick={() => {
setActiveTabIndex(i);
}}
key={i}
>
{tab.props.title}
</button>
))}
</div>
<div className="tab-indicator-container">
<div
className="tab-indicator"
style={{
width: 100 / props.children.length + "%",
transform: `translateX(${activeTabIndex * 100}%)`
}}
/>
</div>
<div className="tab-content">{activeTab.props.children}</div>
</div>
);
};
export default function App() {
return (
<div className="App">
<h1>Tab Component Demo</h1>
<h2>Start adding tabs to see some magic happen!</h2>
<Tabs>
<div title="Tab 1">
Ut condimentum, ex sit amet rutrum ultrices, nisi velit condimentum
mi, et sagittis turpis ligula ut neque. Nunc ut arcu velit. Sed
suscipit nisl est, ut scelerisque elit pretium et.{" "}
</div>
<div title="Tab 2">
Phasellus vel nisi lectus. Curabitur ac efficitur quam. Aliquam
faucibus, nibh non auctor auctor, lectus leo cursus massa, ac ornare
dolor ante eu libero.{" "}
</div>
<div title="Tab 3">
Aliquam erat volutpat. Sed id pulvinar magna. Aenean scelerisque ex
vitae faucibus faucibus. Proin rutrum est eget odio faucibus tempor.
Nulla ut tellus non urna congue finibus.{" "}
</div>
</Tabs>
</div>
);
}
样式.css
.App {
font-family: sans-serif;
text-align: center;
}
.tabs {
display: flex;
align-items: center;
justify-content: center;
}
.tab-btn {
display: block;
flex: 1;
padding: 8px 20px;
background: #eee;
border: 0;
}
.tab-indicator-container {
display: flex;
background: #eee;
margin-bottom: 10px;
}
.tab-indicator {
height: 3px;
background: #007bff;
transition: transform 0.2s;
}
.tab-content {
padding: 10px;
}
结论
标签页可让用户更轻松地浏览您的应用,并且是任何应用的 UI 结构的重要组成部分。大多数框架在其设计中都实现了自己的标签页版本,这些标签页遵循不同的模式。
我希望您喜欢本指南并期待构建一些自定义组件。
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~