Tabs标签页

    提供平级的区域将大块内容进行收纳和展现,保持界面整洁。

    Ant Design 依次提供了三级选项卡,分别用于不同的场景。

    • 卡片式的页签,提供可关闭的样式,常用于容器顶部。

    • 标准线条式页签,用于容器内部的主功能切换,这是最常用的 Tabs。

    • RadioButton 可作为更次级的页签来使用。

    默认选中第一项。

    Tabs 标签页 - 图2

    禁用

    禁用某一项。

    1. const TabPane = Tabs.TabPane;
    2. ReactDOM.render(
    3. <Tabs defaultActiveKey="1">
    4. <TabPane tab="Tab 1" key="1">
    5. Tab 1
    6. </TabPane>
    7. <TabPane tab="Tab 2" disabled key="2">
    8. Tab 2
    9. </TabPane>
    10. <TabPane tab="Tab 3" key="3">
    11. Tab 3
    12. </TabPane>
    13. </Tabs>,
    14. mountNode,
    15. );

    有图标的标签。

    1. import { Tabs, Icon } from 'antd';
    2. const TabPane = Tabs.TabPane;
    3. ReactDOM.render(
    4. <Tabs defaultActiveKey="2">
    5. <TabPane
    6. tab={
    7. <span>
    8. <Icon type="apple" />
    9. Tab 1
    10. </span>
    11. }
    12. key="1"
    13. >
    14. Tab 1
    15. </TabPane>
    16. <TabPane
    17. tab={
    18. <span>
    19. <Icon type="android" />
    20. Tab 2
    21. </span>
    22. }
    23. key="2"
    24. >
    25. Tab 2
    26. </TabPane>
    27. </Tabs>,
    28. mountNode,
    29. );

    滑动

    可以左右、上下滑动,容纳更多标签。

    1. import { Tabs, Radio } from 'antd';
    2. const TabPane = Tabs.TabPane;
    3. class SlidingTabsDemo extends React.Component {
    4. constructor(props) {
    5. super(props);
    6. this.state = {
    7. mode: 'top',
    8. };
    9. }
    10. handleModeChange = e => {
    11. const mode = e.target.value;
    12. this.setState({ mode });
    13. };
    14. render() {
    15. const { mode } = this.state;
    16. return (
    17. <div>
    18. <Radio.Group onChange={this.handleModeChange} value={mode} style={{ marginBottom: 8 }}>
    19. <Radio.Button value="top">Horizontal</Radio.Button>
    20. <Radio.Button value="left">Vertical</Radio.Button>
    21. </Radio.Group>
    22. <Tabs defaultActiveKey="1" tabPosition={mode} style={{ height: 220 }}>
    23. <TabPane tab="Tab 1" key="1">
    24. Content of tab 1
    25. </TabPane>
    26. <TabPane tab="Tab 2" key="2">
    27. Content of tab 2
    28. </TabPane>
    29. <TabPane tab="Tab 3" key="3">
    30. Content of tab 3
    31. </TabPane>
    32. <TabPane tab="Tab 4" key="4">
    33. Content of tab 4
    34. </TabPane>
    35. <TabPane tab="Tab 5" key="5">
    36. Content of tab 5
    37. </TabPane>
    38. <TabPane tab="Tab 6" key="6">
    39. Content of tab 6
    40. </TabPane>
    41. <TabPane tab="Tab 7" key="7">
    42. Content of tab 7
    43. </TabPane>
    44. <TabPane tab="Tab 8" key="8">
    45. Content of tab 8
    46. </TabPane>
    47. <TabPane tab="Tab 9" key="9">
    48. Content of tab 9
    49. </TabPane>
    50. <TabPane tab="Tab 10" key="10">
    51. Content of tab 10
    52. </TabPane>
    53. <TabPane tab="Tab 11" key="11">
    54. Content of tab 11
    55. </TabPane>
    56. </Tabs>
    57. </div>
    58. );
    59. }
    60. }
    61. ReactDOM.render(<SlidingTabsDemo />, mountNode);

    Tabs 标签页 - 图5

    可以在页签右边添加附加操作。

    大小

    大号页签用在页头区域,小号用在弹出框等较狭窄的容器内。

    1. import { Tabs, Radio } from 'antd';
    2. const { TabPane } = Tabs;
    3. class Demo extends React.Component {
    4. state = { size: 'small' };
    5. onChange = e => {
    6. this.setState({ size: e.target.value });
    7. };
    8. render() {
    9. const { size } = this.state;
    10. return (
    11. <div>
    12. <Radio.Group value={size} onChange={this.onChange} style={{ marginBottom: 16 }}>
    13. <Radio.Button value="small">Small</Radio.Button>
    14. <Radio.Button value="default">Default</Radio.Button>
    15. <Radio.Button value="large">Large</Radio.Button>
    16. </Radio.Group>
    17. <Tabs defaultActiveKey="1" size={size}>
    18. <TabPane tab="Tab 1" key="1">
    19. Content of tab 1
    20. </TabPane>
    21. <TabPane tab="Tab 2" key="2">
    22. Content of tab 2
    23. </TabPane>
    24. <TabPane tab="Tab 3" key="3">
    25. Content of tab 3
    26. </TabPane>
    27. </Tabs>
    28. </div>
    29. );
    30. }
    31. }
    32. ReactDOM.render(<Demo />, mountNode);

    Tabs 标签页 - 图7

    有四个位置,tabPosition="left|right|top|bottom"

    1. import { Tabs, Select } from 'antd';
    2. const TabPane = Tabs.TabPane;
    3. class Demo extends React.Component {
    4. state = {
    5. tabPosition: 'top',
    6. };
    7. changeTabPosition = tabPosition => {
    8. this.setState({ tabPosition });
    9. };
    10. render() {
    11. return (
    12. <div>
    13. <div style={{ marginBottom: 16 }}>
    14. Tab position
    15. <Select
    16. value={this.state.tabPosition}
    17. onChange={this.changeTabPosition}
    18. dropdownMatchSelectWidth={false}
    19. >
    20. <Option value="top">top</Option>
    21. <Option value="bottom">bottom</Option>
    22. <Option value="left">left</Option>
    23. <Option value="right">right</Option>
    24. </Select>
    25. </div>
    26. <Tabs tabPosition={this.state.tabPosition}>
    27. <TabPane tab="Tab 1" key="1">
    28. Content of Tab 1
    29. </TabPane>
    30. <TabPane tab="Tab 2" key="2">
    31. Content of Tab 2
    32. </TabPane>
    33. <TabPane tab="Tab 3" key="3">
    34. Content of Tab 3
    35. </TabPane>
    36. </Tabs>
    37. </div>
    38. );
    39. }
    40. }
    41. ReactDOM.render(<Demo />, mountNode);

    卡片式页签

    另一种样式的页签,不提供对应的垂直样式。

    1. import { Tabs } from 'antd';
    2. const TabPane = Tabs.TabPane;
    3. function callback(key) {
    4. console.log(key);
    5. }
    6. ReactDOM.render(
    7. <Tabs onChange={callback} type="card">
    8. <TabPane tab="Tab 1" key="1">
    9. Content of Tab Pane 1
    10. </TabPane>
    11. <TabPane tab="Tab 2" key="2">
    12. Content of Tab Pane 2
    13. </TabPane>
    14. <TabPane tab="Tab 3" key="3">
    15. Content of Tab Pane 3
    16. </TabPane>
    17. </Tabs>,
    18. mountNode,
    19. );

    只有卡片样式的页签支持新增和关闭选项。使用 closable={false} 禁止关闭。

    Tabs 标签页 - 图10

    卡片式页签容器

    用于容器顶部,需要一点额外的样式覆盖。

    1. import { Tabs } from 'antd';
    2. const TabPane = Tabs.TabPane;
    3. ReactDOM.render(
    4. <div className="card-container">
    5. <Tabs type="card">
    6. <TabPane tab="Tab Title 1" key="1">
    7. <p>Content of Tab Pane 1</p>
    8. <p>Content of Tab Pane 1</p>
    9. <p>Content of Tab Pane 1</p>
    10. </TabPane>
    11. <TabPane tab="Tab Title 2" key="2">
    12. <p>Content of Tab Pane 2</p>
    13. <p>Content of Tab Pane 2</p>
    14. <p>Content of Tab Pane 2</p>
    15. </TabPane>
    16. <TabPane tab="Tab Title 3" key="3">
    17. <p>Content of Tab Pane 3</p>
    18. <p>Content of Tab Pane 3</p>
    19. <p>Content of Tab Pane 3</p>
    20. </TabPane>
    21. </Tabs>
    22. </div>,
    23. mountNode,
    24. );
    1. .card-container > .ant-tabs-card > .ant-tabs-content {
    2. height: 120px;
    3. margin-top: -16px;
    4. }
    5. .card-container > .ant-tabs-card > .ant-tabs-content > .ant-tabs-tabpane {
    6. background: #fff;
    7. padding: 16px;
    8. }
    9. .card-container > .ant-tabs-card > .ant-tabs-bar {
    10. border-color: #fff;
    11. }
    12. .card-container > .ant-tabs-card > .ant-tabs-bar .ant-tabs-tab {
    13. border-color: transparent;
    14. background: transparent;
    15. }
    16. .card-container > .ant-tabs-card > .ant-tabs-bar .ant-tabs-tab-active {
    17. border-color: #fff;
    18. background: #fff;
    19. }

    隐藏默认的页签增加图标,给自定义触发器绑定事件。

    1. import { Tabs, Button } from 'antd';
    2. const TabPane = Tabs.TabPane;
    3. class Demo extends React.Component {
    4. constructor(props) {
    5. super(props);
    6. this.newTabIndex = 0;
    7. const panes = [
    8. { title: 'Tab 1', content: 'Content of Tab Pane 1', key: '1' },
    9. { title: 'Tab 2', content: 'Content of Tab Pane 2', key: '2' },
    10. ];
    11. this.state = {
    12. activeKey: panes[0].key,
    13. panes,
    14. };
    15. }
    16. onChange = activeKey => {
    17. this.setState({ activeKey });
    18. };
    19. onEdit = (targetKey, action) => {
    20. this[action](targetKey);
    21. };
    22. add = () => {
    23. const panes = this.state.panes;
    24. const activeKey = `newTab${this.newTabIndex++}`;
    25. panes.push({ title: 'New Tab', content: 'New Tab Pane', key: activeKey });
    26. this.setState({ panes, activeKey });
    27. };
    28. remove = targetKey => {
    29. let activeKey = this.state.activeKey;
    30. let lastIndex;
    31. this.state.panes.forEach((pane, i) => {
    32. if (pane.key === targetKey) {
    33. lastIndex = i - 1;
    34. }
    35. });
    36. const panes = this.state.panes.filter(pane => pane.key !== targetKey);
    37. if (panes.length && activeKey === targetKey) {
    38. if (lastIndex >= 0) {
    39. activeKey = panes[lastIndex].key;
    40. } else {
    41. activeKey = panes[0].key;
    42. }
    43. }
    44. };
    45. render() {
    46. return (
    47. <div>
    48. <div style={{ marginBottom: 16 }}>
    49. <Button onClick={this.add}>ADD</Button>
    50. </div>
    51. <Tabs
    52. hideAdd
    53. activeKey={this.state.activeKey}
    54. type="editable-card"
    55. onEdit={this.onEdit}
    56. >
    57. {this.state.panes.map(pane => (
    58. <TabPane tab={pane.title} key={pane.key}>
    59. {pane.content}
    60. </TabPane>
    61. ))}
    62. </Tabs>
    63. </div>
    64. );
    65. }
    66. }
    67. ReactDOM.render(<Demo />, mountNode);

    Tabs 标签页 - 图12

    自定义页签头

    使用 react-sticky 组件实现吸顶效果。

    使用 react-dnd 实现标签可拖拽。

    1. import { Tabs } from 'antd';
    2. import { DragDropContextProvider, DragSource, DropTarget } from 'react-dnd';
    3. import HTML5Backend from 'react-dnd-html5-backend';
    4. const TabPane = Tabs.TabPane;
    5. // Drag & Drop node
    6. class TabNode extends React.Component {
    7. render() {
    8. const { connectDragSource, connectDropTarget, children } = this.props;
    9. return connectDragSource(connectDropTarget(children));
    10. }
    11. }
    12. const cardTarget = {
    13. drop(props, monitor) {
    14. const dragKey = monitor.getItem().index;
    15. const hoverKey = props.index;
    16. if (dragKey === hoverKey) {
    17. return;
    18. }
    19. props.moveTabNode(dragKey, hoverKey);
    20. monitor.getItem().index = hoverKey;
    21. },
    22. };
    23. const cardSource = {
    24. beginDrag(props) {
    25. return {
    26. id: props.id,
    27. index: props.index,
    28. };
    29. },
    30. };
    31. const WrapTabNode = DropTarget('DND_NODE', cardTarget, connect => ({
    32. connectDropTarget: connect.dropTarget(),
    33. }))(
    34. DragSource('DND_NODE', cardSource, (connect, monitor) => ({
    35. connectDragSource: connect.dragSource(),
    36. isDragging: monitor.isDragging(),
    37. }))(TabNode),
    38. );
    39. class DraggableTabs extends React.Component {
    40. state = {
    41. order: [],
    42. };
    43. moveTabNode = (dragKey, hoverKey) => {
    44. const newOrder = this.state.order.slice();
    45. const { children } = this.props;
    46. React.Children.forEach(children, c => {
    47. if (newOrder.indexOf(c.key) === -1) {
    48. newOrder.push(c.key);
    49. }
    50. });
    51. const dragIndex = newOrder.indexOf(dragKey);
    52. const hoverIndex = newOrder.indexOf(hoverKey);
    53. newOrder.splice(dragIndex, 1);
    54. newOrder.splice(hoverIndex, 0, dragKey);
    55. this.setState({
    56. order: newOrder,
    57. });
    58. };
    59. renderTabBar = (props, DefaultTabBar) => (
    60. <DefaultTabBar {...props}>
    61. {node => (
    62. <WrapTabNode key={node.key} index={node.key} moveTabNode={this.moveTabNode}>
    63. {node}
    64. </WrapTabNode>
    65. )}
    66. </DefaultTabBar>
    67. );
    68. render() {
    69. const { order } = this.state;
    70. const { children } = this.props;
    71. const tabs = [];
    72. React.Children.forEach(children, c => {
    73. tabs.push(c);
    74. });
    75. const orderTabs = tabs.slice().sort((a, b) => {
    76. const orderA = order.indexOf(a.key);
    77. const orderB = order.indexOf(b.key);
    78. if (orderA !== -1 && orderB !== -1) {
    79. return orderA - orderB;
    80. }
    81. if (orderA !== -1) {
    82. return -1;
    83. }
    84. if (orderB !== -1) {
    85. return 1;
    86. }
    87. const ia = tabs.indexOf(a);
    88. const ib = tabs.indexOf(b);
    89. return ia - ib;
    90. });
    91. return (
    92. <DragDropContextProvider backend={HTML5Backend}>
    93. <Tabs renderTabBar={this.renderTabBar} {...this.props}>
    94. {orderTabs}
    95. </Tabs>
    96. </DragDropContextProvider>
    97. );
    98. }
    99. }
    100. ReactDOM.render(
    101. <DraggableTabs>
    102. <TabPane tab="tab 1" key="1">
    103. Content of Tab Pane 1
    104. </TabPane>
    105. <TabPane tab="tab 2" key="2">
    106. Content of Tab Pane 2
    107. </TabPane>
    108. <TabPane tab="tab 3" key="3">
    109. Content of Tab Pane 3
    110. </TabPane>
    111. </DraggableTabs>,
    112. mountNode,
    113. );

    Tabs.TabPane

    参数说明类型默认值
    forceRender被隐藏时是否渲染 DOM 结构booleanfalse
    key对应 activeKeystring
    tab选项卡头显示文字string|ReactNode