refactor: tabs
parent
ba8a128943
commit
603c91a81a
|
@ -16,7 +16,7 @@ Customized bar of tab.
|
||||||
</docs>
|
</docs>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div style="height: 2000px">
|
<div>
|
||||||
<a-tabs v-model:activeKey="activeKey">
|
<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="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>
|
<a-tab-pane key="2" tab="Tab 2" force-render>Content of Tab Pane 2</a-tab-pane>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<demo-sort :cols="1">
|
<demo-sort :cols="1">
|
||||||
<Basic />
|
<Basic />
|
||||||
<Disabled />
|
<Disabled />
|
||||||
|
<Centered />
|
||||||
<Icon />
|
<Icon />
|
||||||
<Slide />
|
<Slide />
|
||||||
<Extra />
|
<Extra />
|
||||||
|
@ -28,6 +29,7 @@ import Position from './position.vue';
|
||||||
import Size from './size.vue';
|
import Size from './size.vue';
|
||||||
import Slide from './slide.vue';
|
import Slide from './slide.vue';
|
||||||
import CustomTabBar from './custom-tab-bar.vue';
|
import CustomTabBar from './custom-tab-bar.vue';
|
||||||
|
import Centered from './centered.vue';
|
||||||
import CN from '../index.zh-CN.md';
|
import CN from '../index.zh-CN.md';
|
||||||
import US from '../index.en-US.md';
|
import US from '../index.en-US.md';
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
@ -40,6 +42,7 @@ export default defineComponent({
|
||||||
CN,
|
CN,
|
||||||
US,
|
US,
|
||||||
components: {
|
components: {
|
||||||
|
Centered,
|
||||||
Basic,
|
Basic,
|
||||||
Card,
|
Card,
|
||||||
CardTop,
|
CardTop,
|
||||||
|
|
|
@ -17,7 +17,7 @@ In order to fit in more tabs, they can slide left and right (or up and down).
|
||||||
</docs>
|
</docs>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div style="width: 500px">
|
<div>
|
||||||
<a-radio-group v-model:value="mode" :style="{ marginBottom: '8px' }">
|
<a-radio-group v-model:value="mode" :style="{ marginBottom: '8px' }">
|
||||||
<a-radio-button value="top">Horizontal</a-radio-button>
|
<a-radio-button value="top">Horizontal</a-radio-button>
|
||||||
<a-radio-button value="left">Vertical</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"
|
v-model:activeKey="activeKey"
|
||||||
:tab-position="mode"
|
:tab-position="mode"
|
||||||
:style="{ height: '200px' }"
|
:style="{ height: '200px' }"
|
||||||
@prevClick="callback"
|
@tabScroll="callback"
|
||||||
@nextClick="callback"
|
|
||||||
>
|
>
|
||||||
<a-tab-pane v-for="i in 30" :key="i" :tab="`Tab-${i}`">Content of tab {{ i }}</a-tab-pane>
|
<a-tab-pane v-for="i in 30" :key="i" :tab="`Tab-${i}`">Content of tab {{ i }}</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
|
|
|
@ -23,17 +23,24 @@ Ant Design has 3 types of Tabs for different situations.
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| activeKey(v-model) | Current TabPane's key | string | - | |
|
| 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"` | |
|
| 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` | } |
|
| hideAdd | Hide plus icon or not. Only works while `type="editable-card"` | boolean | `false` | } |
|
||||||
| size | preset tab bar size | `large` \| `default` \| `small` | `default` | |
|
| 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 | - | |
|
| tabBarStyle | Tab bar style object | object | - | |
|
||||||
| tabPosition | Position of tabs | `top` \| `right` \| `bottom` \| `left` | `top` | |
|
| tabPosition | Position of tabs | `top` \| `right` \| `bottom` \| `left` | `top` | |
|
||||||
| type | Basic style of tabs | `line` \| `card` \| `editable-card` | `line` | |
|
| type | Basic style of tabs | `line` \| `card` \| `editable-card` | `line` | |
|
||||||
| tabBarGutter | The gap between tabs | number | - | |
|
| 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 |
|
| 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 |
|
| forceRender | Forced render of content in tabs, not lazy render after clicking on tabs | boolean | false |
|
||||||
| key | TabPane's key | string | - |
|
| key | TabPane's key | string | - |
|
||||||
| tab | Show text in TabPane's head | string\|slot | - |
|
| tab | Show text in TabPane's head | string\|slot | - |
|
||||||
|
|
||||||
|
### Tabs.TabPane Slots
|
||||||
|
|
||||||
|
| 插槽名称 | 说明 | 参数 |
|
||||||
|
| --------- | ----------------------------------------------- | ---- |
|
||||||
|
| closeIcon | 自定义关闭图标,`在 type="editable-card"`时有效 | - |
|
||||||
|
| tab | Show text in TabPane's head | - |
|
||||||
|
|
|
@ -26,25 +26,32 @@ Ant Design 依次提供了三级选项卡,分别用于不同的场景。
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| activeKey(v-model) | 当前激活 tab 面板的 key | string | 无 | |
|
| activeKey(v-model) | 当前激活 tab 面板的 key | string | 无 | |
|
||||||
| animated | 是否使用动画切换 Tabs,在 `tabPosition=top | bottom` 时有效 | boolean \| {inkBar:boolean, tabPane:boolean} | true, 当 type="card" 时为 false | |
|
| 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 | |
|
| hideAdd | 是否隐藏加号图标,在 `type="editable-card"` 时有效 | boolean | false | |
|
||||||
| size | 大小,提供 `large` `default` 和 `small` 三种大小 | string | 'default' | |
|
| 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 | - | |
|
| tabBarStyle | tab bar 的样式对象 | object | - | |
|
||||||
| tabPosition | 页签位置,可选值有 `top` `right` `bottom` `left` | string | 'top' | |
|
| tabPosition | 页签位置,可选值有 `top` `right` `bottom` `left` | string | 'top' | |
|
||||||
| type | 页签的基本样式,可选 `line`、`card` `editable-card` 类型 | string | 'line' | |
|
| type | 页签的基本样式,可选 `line`、`card` `editable-card` 类型 | string | 'line' | |
|
||||||
| tabBarGutter | tabs 之间的间隙 | number | 无 | |
|
| tabBarGutter | tabs 之间的间隙 | number | 无 | |
|
||||||
|
|
||||||
### 事件
|
### Tabs 插槽
|
||||||
|
|
||||||
| 事件名称 | 说明 | 回调参数 |
|
| 插槽名称 | 说明 | 参数 |
|
||||||
| --------- | ------------------------------------------------------ | ------------------------- |
|
| ------------ | ------------------------------- | ----------------- | --- |
|
||||||
| change | 切换面板的回调 | Function(activeKey) {} |
|
| renderTabBar | 替换 TabBar,用于二次封装标签头 | { DefaultTabBar } | |
|
||||||
| edit | 新增和删除页签的回调,在 `type="editable-card"` 时有效 | (targetKey, action): void |
|
| leftExtra | tab bar 上左侧额外的元素 | - | - |
|
||||||
| nextClick | next 按钮被点击的回调 | Function |
|
| rightExtra | tab bar 上右侧额外的元素 | - | - |
|
||||||
| prevClick | prev 按钮被点击的回调 | Function |
|
| addIcon | 自定义添加按钮 | - | - |
|
||||||
| tabClick | tab 被点击的回调 | Function |
|
| 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
|
### Tabs.TabPane
|
||||||
|
|
||||||
|
@ -53,3 +60,10 @@ Ant Design 依次提供了三级选项卡,分别用于不同的场景。
|
||||||
| forceRender | 被隐藏时是否渲染 DOM 结构 | boolean | false |
|
| forceRender | 被隐藏时是否渲染 DOM 结构 | boolean | false |
|
||||||
| key | 对应 activeKey | string | 无 |
|
| key | 对应 activeKey | string | 无 |
|
||||||
| tab | 选项卡头显示文字 | string\|slot | 无 |
|
| tab | 选项卡头显示文字 | string\|slot | 无 |
|
||||||
|
|
||||||
|
### Tabs.TabPane 插槽
|
||||||
|
|
||||||
|
| 插槽名称 | 说明 | 参数 |
|
||||||
|
| --------- | ----------------------------------------------- | ---- |
|
||||||
|
| closeIcon | 自定义关闭图标,`在 type="editable-card"`时有效 | - |
|
||||||
|
| tab | 选项卡头显示文字 | - |
|
||||||
|
|
|
@ -9,6 +9,7 @@ import classNames from '../../../_util/classNames';
|
||||||
import { defineComponent, watch, computed, onMounted } from 'vue';
|
import { defineComponent, watch, computed, onMounted } from 'vue';
|
||||||
import PropTypes from '../../../_util/vue-types';
|
import PropTypes from '../../../_util/vue-types';
|
||||||
import useState from '../../../_util/hooks/useState';
|
import useState from '../../../_util/hooks/useState';
|
||||||
|
import { EllipsisOutlined } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
export interface OperationNodeProps {
|
export interface OperationNodeProps {
|
||||||
prefixCls: string;
|
prefixCls: string;
|
||||||
|
@ -124,7 +125,7 @@ export default defineComponent({
|
||||||
tabs,
|
tabs,
|
||||||
locale,
|
locale,
|
||||||
mobile,
|
mobile,
|
||||||
moreIcon = slots.moreIcon?.() || 'More',
|
moreIcon = slots.moreIcon?.() || <EllipsisOutlined />,
|
||||||
moreTransitionName,
|
moreTransitionName,
|
||||||
editable,
|
editable,
|
||||||
tabBarGutter,
|
tabBarGutter,
|
||||||
|
|
|
@ -96,7 +96,6 @@ export default defineComponent({
|
||||||
|
|
||||||
const [tabSizes, setTabSizes] = useRafState<TabSizeMap>(new Map());
|
const [tabSizes, setTabSizes] = useRafState<TabSizeMap>(new Map());
|
||||||
const tabOffsets = useOffsets(tabs, tabSizes);
|
const tabOffsets = useOffsets(tabs, tabSizes);
|
||||||
|
|
||||||
// ========================== Util =========================
|
// ========================== Util =========================
|
||||||
const operationsHiddenClassName = computed(() => `${prefixCls.value}-nav-operations-hidden`);
|
const operationsHiddenClassName = computed(() => `${prefixCls.value}-nav-operations-hidden`);
|
||||||
|
|
||||||
|
@ -234,14 +233,14 @@ export default defineComponent({
|
||||||
|
|
||||||
if (['top', 'bottom'].includes(props.tabPosition)) {
|
if (['top', 'bottom'].includes(props.tabPosition)) {
|
||||||
unit = 'width';
|
unit = 'width';
|
||||||
basicSize = wrapperContentWidth.value;
|
basicSize = wrapperWidth.value;
|
||||||
tabContentSize = wrapperContentWidth.value;
|
tabContentSize = wrapperContentWidth.value;
|
||||||
addSize = addWidth.value;
|
addSize = addWidth.value;
|
||||||
position = props.rtl ? 'right' : 'left';
|
position = props.rtl ? 'right' : 'left';
|
||||||
transformSize = Math.abs(transformLeft.value);
|
transformSize = Math.abs(transformLeft.value);
|
||||||
} else {
|
} else {
|
||||||
unit = 'height';
|
unit = 'height';
|
||||||
basicSize = wrapperContentHeight.value;
|
basicSize = wrapperHeight.value;
|
||||||
tabContentSize = wrapperContentHeight.value;
|
tabContentSize = wrapperContentHeight.value;
|
||||||
addSize = addHeight.value;
|
addSize = addHeight.value;
|
||||||
position = 'top';
|
position = 'top';
|
||||||
|
@ -255,7 +254,7 @@ export default defineComponent({
|
||||||
|
|
||||||
const tabsVal = tabs.value;
|
const tabsVal = tabs.value;
|
||||||
if (!tabsVal.length) {
|
if (!tabsVal.length) {
|
||||||
[visibleStart.value, visibleEnd.value] = [0, 0];
|
return ([visibleStart.value, visibleEnd.value] = [0, 0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const len = tabsVal.length;
|
const len = tabsVal.length;
|
||||||
|
@ -267,7 +266,6 @@ export default defineComponent({
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let startIndex = 0;
|
let startIndex = 0;
|
||||||
for (let i = len - 1; i >= 0; i -= 1) {
|
for (let i = len - 1; i >= 0; i -= 1) {
|
||||||
const offset = tabOffsets.value.get(tabsVal[i].key) || DEFAULT_SIZE;
|
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 = () => {
|
const onListHolderResize = () => {
|
||||||
|
@ -473,7 +471,6 @@ export default defineComponent({
|
||||||
></TabNode>
|
></TabNode>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import supportsPassive from 'ant-design-vue/es/_util/supportsPassive';
|
|
||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
import { ref, onBeforeUnmount, onMounted } from 'vue';
|
import { ref, onBeforeUnmount, onMounted } from 'vue';
|
||||||
import useState from '../../../_util/hooks/useState';
|
import useState from '../../../_util/hooks/useState';
|
||||||
|
@ -131,11 +130,7 @@ export default function useTouchMove(
|
||||||
|
|
||||||
// No need to clean up since element removed
|
// No need to clean up since element removed
|
||||||
domRef.value?.addEventListener('touchstart', onProxyTouchStart, { passive: false });
|
domRef.value?.addEventListener('touchstart', onProxyTouchStart, { passive: false });
|
||||||
domRef.value?.addEventListener(
|
domRef.value?.addEventListener('wheel', onProxyWheel, { passive: false });
|
||||||
'wheel',
|
|
||||||
onProxyWheel,
|
|
||||||
supportsPassive ? { passive: true } : false,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
|
Loading…
Reference in New Issue