refactor: tabs

refactor-tabs
tangjinzhou 2021-10-06 16:56:12 +08:00
parent ba8a128943
commit 603c91a81a
8 changed files with 56 additions and 33 deletions

View File

@ -16,7 +16,7 @@ Customized bar of tab.
</docs>
<template>
<div style="height: 2000px">
<div>
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="Tab 1" style="height: 200px">Content of Tab Pane 1</a-tab-pane>
<a-tab-pane key="2" tab="Tab 2" force-render>Content of Tab Pane 2</a-tab-pane>

View File

@ -2,6 +2,7 @@
<demo-sort :cols="1">
<Basic />
<Disabled />
<Centered />
<Icon />
<Slide />
<Extra />
@ -28,6 +29,7 @@ import Position from './position.vue';
import Size from './size.vue';
import Slide from './slide.vue';
import CustomTabBar from './custom-tab-bar.vue';
import Centered from './centered.vue';
import CN from '../index.zh-CN.md';
import US from '../index.en-US.md';
import { defineComponent } from 'vue';
@ -40,6 +42,7 @@ export default defineComponent({
CN,
US,
components: {
Centered,
Basic,
Card,
CardTop,

View File

@ -17,7 +17,7 @@ In order to fit in more tabs, they can slide left and right (or up and down).
</docs>
<template>
<div style="width: 500px">
<div>
<a-radio-group v-model:value="mode" :style="{ marginBottom: '8px' }">
<a-radio-button value="top">Horizontal</a-radio-button>
<a-radio-button value="left">Vertical</a-radio-button>
@ -26,8 +26,7 @@ In order to fit in more tabs, they can slide left and right (or up and down).
v-model:activeKey="activeKey"
:tab-position="mode"
:style="{ height: '200px' }"
@prevClick="callback"
@nextClick="callback"
@tabScroll="callback"
>
<a-tab-pane v-for="i in 30" :key="i" :tab="`Tab-${i}`">Content of tab {{ i }}</a-tab-pane>
</a-tabs>

View File

@ -23,17 +23,24 @@ Ant Design has 3 types of Tabs for different situations.
| --- | --- | --- | --- | --- |
| activeKey(v-model) | Current TabPane's key | string | - | |
| animated | Whether to change tabs with animation. Only works while `tabPosition="top"\|"bottom"` | boolean \| {inkBar:boolean, tabPane:boolean} | `true`, `false` when `type="card"` | |
| defaultActiveKey | Initial active TabPane's key, if `activeKey` is not set. | string | - | |
| hideAdd | Hide plus icon or not. Only works while `type="editable-card"` | boolean | `false` | } |
| size | preset tab bar size | `large` \| `default` \| `small` | `default` | |
| leftExtra | Extra content in tab bar left | v-slot:leftExtra | - | 3.0 |
| rightExtra | Extra content in tab bar right | v-slot:rightExtra | - | 3.0 |
| tabBarStyle | Tab bar style object | object | - | |
| tabPosition | Position of tabs | `top` \| `right` \| `bottom` \| `left` | `top` | |
| type | Basic style of tabs | `line` \| `card` \| `editable-card` | `line` | |
| tabBarGutter | The gap between tabs | number | - | |
### Events
### Tabs Slots
| 插槽名称 | 说明 | 参数 |
| ------------ | ------------------------------ | ----------------- | --- |
| renderTabBar | Replace the TabBar | { DefaultTabBar } | |
| leftExtra | Extra content in tab bar left | - | - |
| rightExtra | Extra content in tab bar right | - | - |
| addIcon | Customize add icon | - | - |
| moreIcon | The custom icon of ellipsis | - | - |
### Tabs Events
| Events Name | Description | Arguments |
| --- | --- | --- |
@ -50,3 +57,10 @@ Ant Design has 3 types of Tabs for different situations.
| forceRender | Forced render of content in tabs, not lazy render after clicking on tabs | boolean | false |
| key | TabPane's key | string | - |
| tab | Show text in TabPane's head | string\|slot | - |
### Tabs.TabPane Slots
| 插槽名称 | 说明 | 参数 |
| --------- | ----------------------------------------------- | ---- |
| closeIcon | 自定义关闭图标,`在 type="editable-card"`时有效 | - |
| tab | Show text in TabPane's head | - |

View File

@ -26,25 +26,32 @@ Ant Design 依次提供了三级选项卡,分别用于不同的场景。
| --- | --- | --- | --- | --- | --- |
| activeKey(v-model) | 当前激活 tab 面板的 key | string | 无 | |
| animated | 是否使用动画切换 Tabs`tabPosition=top | bottom` 时有效 | boolean \| {inkBar:boolean, tabPane:boolean} | true, 当 type="card" 时为 false | |
| defaultActiveKey | 初始化选中面板的 key如果没有设置 activeKey | string | 第一个面板 | |
| centered | 标签居中展示 | boolean | false | 3.0 |
| hideAdd | 是否隐藏加号图标,在 `type="editable-card"` 时有效 | boolean | false | |
| size | 大小,提供 `large` `default``small` 三种大小 | string | 'default' | |
| leftExtra | tab bar 上左侧额外的元素 | v-slot:leftExtra | - | 3.0 |
| rightExtra | tab bar 上右侧额外的元素 | v-slot:rightExtra | - | 3.0 |
| tabBarStyle | tab bar 的样式对象 | object | - | |
| tabPosition | 页签位置,可选值有 `top` `right` `bottom` `left` | string | 'top' | |
| type | 页签的基本样式,可选 `line`、`card` `editable-card` 类型 | string | 'line' | |
| tabBarGutter | tabs 之间的间隙 | number | 无 | |
### 事件
### Tabs 插槽
| 事件名称 | 说明 | 回调参数 |
| --------- | ------------------------------------------------------ | ------------------------- |
| change | 切换面板的回调 | Function(activeKey) {} |
| edit | 新增和删除页签的回调,在 `type="editable-card"` 时有效 | (targetKey, action): void |
| nextClick | next 按钮被点击的回调 | Function |
| prevClick | prev 按钮被点击的回调 | Function |
| tabClick | tab 被点击的回调 | Function |
| 插槽名称 | 说明 | 参数 |
| ------------ | ------------------------------- | ----------------- | --- |
| renderTabBar | 替换 TabBar用于二次封装标签头 | { DefaultTabBar } | |
| leftExtra | tab bar 上左侧额外的元素 | - | - |
| rightExtra | tab bar 上右侧额外的元素 | - | - |
| addIcon | 自定义添加按钮 | - | - |
| moreIcon | 自定义折叠 icon | - | - |
### Tabs 事件
| 事件名称 | 说明 | 回调参数 |
| --- | --- | --- |
| change | 切换面板的回调 | Function(activeKey) {} |
| edit | 新增和删除页签的回调,在 `type="editable-card"` 时有效 | (targetKey, action): void |
| tabScroll | 滚动 TabBar 是触发 | { direction: 'left' \| 'right' \| 'top' \| 'bottom' } |
| tabClick | tab 被点击的回调 | Function |
### Tabs.TabPane
@ -53,3 +60,10 @@ Ant Design 依次提供了三级选项卡,分别用于不同的场景。
| forceRender | 被隐藏时是否渲染 DOM 结构 | boolean | false |
| key | 对应 activeKey | string | 无 |
| tab | 选项卡头显示文字 | string\|slot | 无 |
### Tabs.TabPane 插槽
| 插槽名称 | 说明 | 参数 |
| --------- | ----------------------------------------------- | ---- |
| closeIcon | 自定义关闭图标,`在 type="editable-card"`时有效 | - |
| tab | 选项卡头显示文字 | - |

View File

@ -9,6 +9,7 @@ import classNames from '../../../_util/classNames';
import { defineComponent, watch, computed, onMounted } from 'vue';
import PropTypes from '../../../_util/vue-types';
import useState from '../../../_util/hooks/useState';
import { EllipsisOutlined } from '@ant-design/icons-vue';
export interface OperationNodeProps {
prefixCls: string;
@ -124,7 +125,7 @@ export default defineComponent({
tabs,
locale,
mobile,
moreIcon = slots.moreIcon?.() || 'More',
moreIcon = slots.moreIcon?.() || <EllipsisOutlined />,
moreTransitionName,
editable,
tabBarGutter,

View File

@ -96,7 +96,6 @@ export default defineComponent({
const [tabSizes, setTabSizes] = useRafState<TabSizeMap>(new Map());
const tabOffsets = useOffsets(tabs, tabSizes);
// ========================== Util =========================
const operationsHiddenClassName = computed(() => `${prefixCls.value}-nav-operations-hidden`);
@ -234,14 +233,14 @@ export default defineComponent({
if (['top', 'bottom'].includes(props.tabPosition)) {
unit = 'width';
basicSize = wrapperContentWidth.value;
basicSize = wrapperWidth.value;
tabContentSize = wrapperContentWidth.value;
addSize = addWidth.value;
position = props.rtl ? 'right' : 'left';
transformSize = Math.abs(transformLeft.value);
} else {
unit = 'height';
basicSize = wrapperContentHeight.value;
basicSize = wrapperHeight.value;
tabContentSize = wrapperContentHeight.value;
addSize = addHeight.value;
position = 'top';
@ -255,7 +254,7 @@ export default defineComponent({
const tabsVal = tabs.value;
if (!tabsVal.length) {
[visibleStart.value, visibleEnd.value] = [0, 0];
return ([visibleStart.value, visibleEnd.value] = [0, 0]);
}
const len = tabsVal.length;
@ -267,7 +266,6 @@ export default defineComponent({
break;
}
}
let startIndex = 0;
for (let i = len - 1; i >= 0; i -= 1) {
const offset = tabOffsets.value.get(tabsVal[i].key) || DEFAULT_SIZE;
@ -277,7 +275,7 @@ export default defineComponent({
}
}
[visibleStart.value, visibleEnd.value] = [startIndex, endIndex];
return ([visibleStart.value, visibleEnd.value] = [startIndex, endIndex]);
});
const onListHolderResize = () => {
@ -473,7 +471,6 @@ export default defineComponent({
></TabNode>
);
});
return (
<div
ref={ref}

View File

@ -1,4 +1,3 @@
import supportsPassive from 'ant-design-vue/es/_util/supportsPassive';
import type { Ref } from 'vue';
import { ref, onBeforeUnmount, onMounted } from 'vue';
import useState from '../../../_util/hooks/useState';
@ -131,11 +130,7 @@ export default function useTouchMove(
// No need to clean up since element removed
domRef.value?.addEventListener('touchstart', onProxyTouchStart, { passive: false });
domRef.value?.addEventListener(
'wheel',
onProxyWheel,
supportsPassive ? { passive: true } : false,
);
domRef.value?.addEventListener('wheel', onProxyWheel, { passive: false });
});
onBeforeUnmount(() => {