mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-05-23 15:09:16 +08:00
[new feature] Tab: add name prop (#3762)
This commit is contained in:
parent
2389ac06ba
commit
b802047e24
@ -32,6 +32,26 @@ export default {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Match By Name
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-tabs v-model="activeName">
|
||||||
|
<van-tab title="tab 1" name="a">content of tab 1</van-tab>
|
||||||
|
<van-tab title="tab 2" name="b">content of tab 2</van-tab>
|
||||||
|
<van-tab title="tab 3" name="c">content of tab 3</van-tab>
|
||||||
|
</van-tabs>
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeName: 'a'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Swipe Tabs
|
### Swipe Tabs
|
||||||
|
|
||||||
By default more than 4 tabs, you can scroll through the tabs. You can set `swipe-threshold` attribute to customize threshold number.
|
By default more than 4 tabs, you can scroll through the tabs. You can set `swipe-threshold` attribute to customize threshold number.
|
||||||
@ -59,7 +79,7 @@ You can set `disabled` attribute on the corresponding `van-tab`.
|
|||||||
```javascript
|
```javascript
|
||||||
export default {
|
export default {
|
||||||
methods: {
|
methods: {
|
||||||
onClickDisabled(index, title) {
|
onClickDisabled(name, title) {
|
||||||
this.$toast(title + ' is disabled');
|
this.$toast(title + ' is disabled');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,7 +111,7 @@ Tabs styled as cards.
|
|||||||
```javascript
|
```javascript
|
||||||
export default {
|
export default {
|
||||||
methods: {
|
methods: {
|
||||||
onClick(index, title) {
|
onClick(name, title) {
|
||||||
this.$toast(title);
|
this.$toast(title);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,7 +175,7 @@ In swipeable mode, you can switch tabs with swipe gestrue in the content
|
|||||||
|
|
||||||
| Attribute | Description | Type | Default |
|
| Attribute | Description | Type | Default |
|
||||||
|------|------|------|------|
|
|------|------|------|------|
|
||||||
| v-model | Index of active tab | `String` `Number` | `0` |
|
| v-model | Index of active tab | `String | Number` | `0` |
|
||||||
| type | Can be set to `line` `card` | `String` | `line` |
|
| type | Can be set to `line` `card` | `String` | `line` |
|
||||||
| duration | Toggle tab's animation time | `Number` | `0.3` | - |
|
| duration | Toggle tab's animation time | `Number` | `0.3` | - |
|
||||||
| background | Background color | `String` | `white` |
|
| background | Background color | `String` | `white` |
|
||||||
@ -177,6 +197,7 @@ In swipeable mode, you can switch tabs with swipe gestrue in the content
|
|||||||
|
|
||||||
| Attribute | Description | Type | Default |
|
| Attribute | Description | Type | Default |
|
||||||
|------|------|------|------|
|
|------|------|------|------|
|
||||||
|
| name | Identifier | `String | Number` | Index of tab |
|
||||||
| title | Title | `String` | - |
|
| title | Title | `String` | - |
|
||||||
| disabled | Whether to disable tab | `Boolean` | `false` |
|
| disabled | Whether to disable tab | `Boolean` | `false` |
|
||||||
|
|
||||||
@ -198,7 +219,7 @@ In swipeable mode, you can switch tabs with swipe gestrue in the content
|
|||||||
|
|
||||||
| Event | Description | Arguments |
|
| Event | Description | Arguments |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| click | Triggered when click tab | index:index of current tab,title: tab title |
|
| click | Triggered when click tab | name:name of current tab,title: tab title |
|
||||||
| change | Triggered when active tab changed | index:index of current tab,title: tab title |
|
| change | Triggered when active tab changed | name:name of current tab,title: tab title |
|
||||||
| disabled | Triggered when click disabled tab | index:index of current tab, title: tab title |
|
| disabled | Triggered when click disabled tab | name:name of current tab, title: tab title |
|
||||||
| scroll | Triggered when tab scroll in sticky mode | Object: { scrollTop, isFixed } |
|
| scroll | Triggered when tab scroll in sticky mode | Object: { scrollTop, isFixed } |
|
||||||
|
@ -12,7 +12,7 @@ Vue.use(Tab).use(Tabs);
|
|||||||
|
|
||||||
### 基础用法
|
### 基础用法
|
||||||
|
|
||||||
默认情况下启用第一个标签,可以通过`v-model`绑定当前激活的标签索引
|
通过`v-model`绑定当前激活标签对应的索引值,默认情况下启用第一个标签
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<van-tabs v-model="active">
|
<van-tabs v-model="active">
|
||||||
@ -33,9 +33,31 @@ export default {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 横向滚动
|
### 通过名称匹配
|
||||||
|
|
||||||
多于 4 个标签时,Tab 可以横向滚动
|
在标签指定`name`属性的情况下,`v-model`的值为当前标签的`name`
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-tabs v-model="activeName">
|
||||||
|
<van-tab title="标签 1" name="a">内容 1</van-tab>
|
||||||
|
<van-tab title="标签 2" name="b">内容 2</van-tab>
|
||||||
|
<van-tab title="标签 3" name="c">内容 3</van-tab>
|
||||||
|
</van-tabs>
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeName: 'a'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 标签栏滚动
|
||||||
|
|
||||||
|
标签数量超过 4 个时,标签栏可以在水平方向上滚动,切换时会自动将当前标签居中
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<van-tabs>
|
<van-tabs>
|
||||||
@ -60,8 +82,8 @@ export default {
|
|||||||
```javascript
|
```javascript
|
||||||
export default {
|
export default {
|
||||||
methods: {
|
methods: {
|
||||||
onClickDisabled(index, title) {
|
onClickDisabled(name, title) {
|
||||||
this.$toast(title + '已被禁用');
|
this.$toast(name + '已被禁用');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -93,7 +115,7 @@ export default {
|
|||||||
```javascript
|
```javascript
|
||||||
export default {
|
export default {
|
||||||
methods: {
|
methods: {
|
||||||
onClick(index, title) {
|
onClick(name, title) {
|
||||||
this.$toast(title);
|
this.$toast(title);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,7 +179,7 @@ export default {
|
|||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
|------|------|------|------|------|
|
|------|------|------|------|------|
|
||||||
| v-model | 当前标签的索引 | `String` `Number` | `0` | - |
|
| v-model | 绑定当前选中标签的标识符 | `String | Number` | `0` | - |
|
||||||
| type | 样式类型,可选值为`card` | `String` | `line` | - |
|
| type | 样式类型,可选值为`card` | `String` | `line` | - |
|
||||||
| duration | 动画时间,单位秒 | `Number` | `0.3` | - |
|
| duration | 动画时间,单位秒 | `Number` | `0.3` | - |
|
||||||
| background | 标签栏背景色 | `String` | `white` | 1.6.5 |
|
| background | 标签栏背景色 | `String` | `white` | 1.6.5 |
|
||||||
@ -179,6 +201,7 @@ export default {
|
|||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
|------|------|------|------|------|
|
|------|------|------|------|------|
|
||||||
|
| name | 标签名称,作为匹配的标识符 | `String | Number` | 标签的索引值 | 2.0.6 |
|
||||||
| title | 标题 | `String` | - | - |
|
| title | 标题 | `String` | - | - |
|
||||||
| disabled | 是否禁用标签 | `Boolean` | `false` | - |
|
| disabled | 是否禁用标签 | `Boolean` | `false` | - |
|
||||||
|
|
||||||
@ -200,7 +223,7 @@ export default {
|
|||||||
|
|
||||||
| 事件名 | 说明 | 回调参数 |
|
| 事件名 | 说明 | 回调参数 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| click | 点击标签时触发 | index:标签索引,title:标题 |
|
| click | 点击标签时触发 | name:标签标识符,title:标题 |
|
||||||
| change | 当前激活的标签改变时触发 | index:标签索引,title:标题 |
|
| change | 当前激活的标签改变时触发 | name:标签标识符,title:标题 |
|
||||||
| disabled | 点击被禁用的标签时触发 | index:标签索引,title:标题 |
|
| disabled | 点击被禁用的标签时触发 | name:标签标识符,title:标题 |
|
||||||
| scroll | 滚动时触发,仅在 sticky 模式下生效 | { scrollTop: 距离顶部位置, isFixed: 是否吸顶 } |
|
| scroll | 滚动时触发,仅在 sticky 模式下生效 | { scrollTop: 距离顶部位置, isFixed: 是否吸顶 } |
|
||||||
|
@ -12,8 +12,31 @@
|
|||||||
</van-tabs>
|
</van-tabs>
|
||||||
</demo-block>
|
</demo-block>
|
||||||
|
|
||||||
|
<demo-block :title="$t('matchByName')">
|
||||||
|
<van-tabs v-model="activeName">
|
||||||
|
<van-tab
|
||||||
|
name="a"
|
||||||
|
:title="$t('tab') + 1"
|
||||||
|
>
|
||||||
|
{{ $t('content') }} 1
|
||||||
|
</van-tab>
|
||||||
|
<van-tab
|
||||||
|
name="b"
|
||||||
|
:title="$t('tab') + 2"
|
||||||
|
>
|
||||||
|
{{ $t('content') }} 2
|
||||||
|
</van-tab>
|
||||||
|
<van-tab
|
||||||
|
name="c"
|
||||||
|
:title="$t('tab') + 3"
|
||||||
|
>
|
||||||
|
{{ $t('content') }} 3
|
||||||
|
</van-tab>
|
||||||
|
</van-tabs>
|
||||||
|
</demo-block>
|
||||||
|
|
||||||
<demo-block :title="$t('title2')">
|
<demo-block :title="$t('title2')">
|
||||||
<van-tabs @scroll="onScroll">
|
<van-tabs>
|
||||||
<van-tab
|
<van-tab
|
||||||
v-for="index in 8"
|
v-for="index in 8"
|
||||||
:title="$t('tab') + index"
|
:title="$t('tab') + index"
|
||||||
@ -124,7 +147,7 @@ export default {
|
|||||||
i18n: {
|
i18n: {
|
||||||
'zh-CN': {
|
'zh-CN': {
|
||||||
tab: '标签 ',
|
tab: '标签 ',
|
||||||
title2: '横向滚动',
|
title2: '标签栏滚动',
|
||||||
title3: '禁用标签',
|
title3: '禁用标签',
|
||||||
title4: '样式风格',
|
title4: '样式风格',
|
||||||
title5: '点击事件',
|
title5: '点击事件',
|
||||||
@ -132,7 +155,8 @@ export default {
|
|||||||
title7: '自定义标签',
|
title7: '自定义标签',
|
||||||
title8: '切换动画',
|
title8: '切换动画',
|
||||||
title9: '滑动切换',
|
title9: '滑动切换',
|
||||||
disabled: ' 已被禁用'
|
disabled: ' 已被禁用',
|
||||||
|
matchByName: '通过名称匹配'
|
||||||
},
|
},
|
||||||
'en-US': {
|
'en-US': {
|
||||||
tab: 'Tab ',
|
tab: 'Tab ',
|
||||||
@ -145,13 +169,15 @@ export default {
|
|||||||
title7: 'Custom Tab',
|
title7: 'Custom Tab',
|
||||||
title8: 'Switch Animation',
|
title8: 'Switch Animation',
|
||||||
title9: 'Swipeable',
|
title9: 'Swipeable',
|
||||||
disabled: ' is disabled'
|
disabled: ' is disabled',
|
||||||
|
matchByName: 'Match By Name'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
active: 2,
|
active: 2,
|
||||||
|
activeName: 'b',
|
||||||
tabs: [1, 2, 3, 4]
|
tabs: [1, 2, 3, 4]
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -163,10 +189,6 @@ export default {
|
|||||||
|
|
||||||
onClick(index, title) {
|
onClick(index, title) {
|
||||||
this.$toast(title);
|
this.$toast(title);
|
||||||
},
|
|
||||||
|
|
||||||
onScroll(e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -8,6 +8,7 @@ export default createComponent({
|
|||||||
mixins: [ChildrenMixin('vanTabs')],
|
mixins: [ChildrenMixin('vanTabs')],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
|
name: [String, Number],
|
||||||
title: String,
|
title: String,
|
||||||
disabled: Boolean
|
disabled: Boolean
|
||||||
},
|
},
|
||||||
@ -19,14 +20,18 @@ export default createComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
selected() {
|
computedName() {
|
||||||
return this.index === this.parent.curActive;
|
return this.name || this.index;
|
||||||
|
},
|
||||||
|
|
||||||
|
isActive() {
|
||||||
|
return this.computedName === this.parent.currentName;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
'parent.curActive'() {
|
'parent.currentIndex'() {
|
||||||
this.inited = this.inited || this.selected;
|
this.inited = this.inited || this.isActive;
|
||||||
},
|
},
|
||||||
|
|
||||||
title() {
|
title() {
|
||||||
@ -41,7 +46,7 @@ export default createComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render(h) {
|
render(h) {
|
||||||
const { slots, selected } = this;
|
const { slots, isActive } = this;
|
||||||
const shouldRender = this.inited || !this.parent.lazyRender;
|
const shouldRender = this.inited || !this.parent.lazyRender;
|
||||||
const Content = [shouldRender ? slots() : h()];
|
const Content = [shouldRender ? slots() : h()];
|
||||||
|
|
||||||
@ -53,8 +58,8 @@ export default createComponent({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
role="tabpanel"
|
role="tabpanel"
|
||||||
aria-hidden={!selected}
|
aria-hidden={!isActive}
|
||||||
class={bem('pane-wrapper', { inactive: !selected })}
|
class={bem('pane-wrapper', { inactive: !isActive })}
|
||||||
>
|
>
|
||||||
<div class={bem('pane')}>{Content}</div>
|
<div class={bem('pane')}>{Content}</div>
|
||||||
</div>
|
</div>
|
||||||
@ -62,7 +67,7 @@ export default createComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div vShow={selected} role="tabpanel" class={bem('pane')}>
|
<div vShow={isActive} role="tabpanel" class={bem('pane')}>
|
||||||
{Content}
|
{Content}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -29,6 +29,29 @@ exports[`renders demo correctly 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="van-tabs van-tabs--line">
|
||||||
|
<div class="van-tabs__wrap van-hairline--top-bottom">
|
||||||
|
<div role="tablist" class="van-tabs__nav van-tabs__nav--line">
|
||||||
|
<div role="tab" class="van-tab"><span class="van-ellipsis">标签 1</span></div>
|
||||||
|
<div role="tab" aria-selected="true" class="van-tab van-tab--active"><span class="van-ellipsis">标签 2</span></div>
|
||||||
|
<div role="tab" class="van-tab"><span class="van-ellipsis">标签 3</span></div>
|
||||||
|
<div class="van-tabs__line" style="width: 0px; transform: translateX(0px) translateX(-50%);"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="van-tabs__content">
|
||||||
|
<div role="tabpanel" class="van-tab__pane" style="display: none;">
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
<div role="tabpanel" class="van-tab__pane" style="">
|
||||||
|
内容 2
|
||||||
|
</div>
|
||||||
|
<div role="tabpanel" class="van-tab__pane" style="display: none;">
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="van-tabs van-tabs--line">
|
<div class="van-tabs van-tabs--line">
|
||||||
<div class="van-tabs__wrap van-tabs__wrap--scrollable van-hairline--top-bottom">
|
<div class="van-tabs__wrap van-tabs__wrap--scrollable van-hairline--top-bottom">
|
||||||
|
@ -136,6 +136,28 @@ exports[`lazy render 2`] = `
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`name prop 1`] = `
|
||||||
|
<div class="van-tabs van-tabs--line">
|
||||||
|
<div class="van-tabs__wrap van-hairline--top-bottom">
|
||||||
|
<div role="tablist" class="van-tabs__nav van-tabs__nav--line">
|
||||||
|
<div role="tab" aria-selected="true" class="van-tab van-tab--active"><span class="van-ellipsis">title1</span></div>
|
||||||
|
<div role="tab" class="van-tab"><span class="van-ellipsis">title2</span></div>
|
||||||
|
<div role="tab" class="van-tab van-tab--disabled"><span class="van-ellipsis">title3</span></div>
|
||||||
|
<div class="van-tabs__line"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="van-tabs__content">
|
||||||
|
<div role="tabpanel" class="van-tab__pane">Text</div>
|
||||||
|
<div role="tabpanel" class="van-tab__pane" style="display: none;">
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
<div role="tabpanel" class="van-tab__pane" style="display: none;">
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`render nav-left & nav-right slot 1`] = `
|
exports[`render nav-left & nav-right slot 1`] = `
|
||||||
<div class="van-tabs van-tabs--line">
|
<div class="van-tabs van-tabs--line">
|
||||||
<div class="van-tabs__wrap van-hairline--top-bottom">
|
<div class="van-tabs__wrap van-hairline--top-bottom">
|
||||||
|
@ -145,3 +145,38 @@ test('border props', async () => {
|
|||||||
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('name prop', async () => {
|
||||||
|
const onClick = jest.fn();
|
||||||
|
const onChange = jest.fn();
|
||||||
|
const onDisabled = jest.fn();
|
||||||
|
|
||||||
|
const wrapper = mount({
|
||||||
|
template: `
|
||||||
|
<van-tabs @click="onClick" @disabled="onDisabled" @change="onChange">
|
||||||
|
<van-tab title="title1" name="a">Text</van-tab>
|
||||||
|
<van-tab title="title2" name="b">Text</van-tab>
|
||||||
|
<van-tab title="title3" name="c" disabled>Text</van-tab>
|
||||||
|
</van-tabs>
|
||||||
|
`,
|
||||||
|
methods: {
|
||||||
|
onClick,
|
||||||
|
onChange,
|
||||||
|
onDisabled
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await later();
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
|
||||||
|
const tabs = wrapper.findAll('.van-tab');
|
||||||
|
tabs.at(1).trigger('click');
|
||||||
|
|
||||||
|
expect(onClick).toHaveBeenCalledWith('b', 'title2');
|
||||||
|
expect(onChange).toHaveBeenCalledWith('b', 'title2');
|
||||||
|
expect(onChange).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
tabs.at(2).trigger('click');
|
||||||
|
expect(onDisabled).toHaveBeenCalledWith('c', 'title3');
|
||||||
|
expect(onChange).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
@ -31,7 +31,7 @@ export default {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Item Name
|
### Match by name
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<van-tabbar v-model="active">
|
<van-tabbar v-model="active">
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
</van-tabbar>
|
</van-tabbar>
|
||||||
</demo-block>
|
</demo-block>
|
||||||
|
|
||||||
<demo-block :title="$t('itemName')">
|
<demo-block :title="$t('matchByName')">
|
||||||
<van-tabbar v-model="activeName">
|
<van-tabbar v-model="activeName">
|
||||||
<van-tabbar-item
|
<van-tabbar-item
|
||||||
name="home"
|
name="home"
|
||||||
@ -97,13 +97,13 @@ export default {
|
|||||||
badge: '显示徽标',
|
badge: '显示徽标',
|
||||||
customIcon: '自定义图标',
|
customIcon: '自定义图标',
|
||||||
customColor: '自定义颜色',
|
customColor: '自定义颜色',
|
||||||
itemName: '通过名称匹配'
|
matchByName: '通过名称匹配'
|
||||||
},
|
},
|
||||||
'en-US': {
|
'en-US': {
|
||||||
badge: 'Show Badge',
|
badge: 'Show Badge',
|
||||||
customIcon: 'Custom Icon',
|
customIcon: 'Custom Icon',
|
||||||
customColor: 'Custom Color',
|
customColor: 'Custom Color',
|
||||||
itemName: 'Item Name'
|
matchByName: 'Match by name'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -9,17 +9,17 @@ export default createComponent({
|
|||||||
|
|
||||||
props: {
|
props: {
|
||||||
count: Number,
|
count: Number,
|
||||||
active: Number,
|
|
||||||
duration: Number,
|
duration: Number,
|
||||||
animated: Boolean,
|
animated: Boolean,
|
||||||
swipeable: Boolean
|
swipeable: Boolean,
|
||||||
|
currentIndex: Number
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
style() {
|
style() {
|
||||||
if (this.animated) {
|
if (this.animated) {
|
||||||
return {
|
return {
|
||||||
transform: `translate3d(${-1 * this.active * 100}%, 0, 0)`,
|
transform: `translate3d(${-1 * this.currentIndex * 100}%, 0, 0)`,
|
||||||
transitionDuration: `${this.duration}s`
|
transitionDuration: `${this.duration}s`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -40,15 +40,15 @@ export default createComponent({
|
|||||||
methods: {
|
methods: {
|
||||||
// watch swipe touch end
|
// watch swipe touch end
|
||||||
onTouchEnd() {
|
onTouchEnd() {
|
||||||
const { direction, deltaX, active } = this;
|
const { direction, deltaX, currentIndex } = this;
|
||||||
|
|
||||||
/* istanbul ignore else */
|
/* istanbul ignore else */
|
||||||
if (direction === 'horizontal' && this.offsetX >= MIN_SWIPE_DISTANCE) {
|
if (direction === 'horizontal' && this.offsetX >= MIN_SWIPE_DISTANCE) {
|
||||||
/* istanbul ignore else */
|
/* istanbul ignore else */
|
||||||
if (deltaX > 0 && active !== 0) {
|
if (deltaX > 0 && currentIndex !== 0) {
|
||||||
this.$emit('change', active - 1);
|
this.$emit('change', currentIndex - 1);
|
||||||
} else if (deltaX < 0 && active !== this.count - 1) {
|
} else if (deltaX < 0 && currentIndex !== this.count - 1) {
|
||||||
this.$emit('change', active + 1);
|
this.$emit('change', currentIndex + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -7,7 +7,7 @@ export default {
|
|||||||
type: String,
|
type: String,
|
||||||
color: String,
|
color: String,
|
||||||
title: String,
|
title: String,
|
||||||
active: Boolean,
|
isActive: Boolean,
|
||||||
ellipsis: Boolean,
|
ellipsis: Boolean,
|
||||||
disabled: Boolean,
|
disabled: Boolean,
|
||||||
scrollable: Boolean,
|
scrollable: Boolean,
|
||||||
@ -19,7 +19,7 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
style() {
|
style() {
|
||||||
const style = {};
|
const style = {};
|
||||||
const { color, active } = this;
|
const { color, isActive } = this;
|
||||||
const isCard = this.type === 'card';
|
const isCard = this.type === 'card';
|
||||||
|
|
||||||
// card theme color
|
// card theme color
|
||||||
@ -27,7 +27,7 @@ export default {
|
|||||||
style.borderColor = color;
|
style.borderColor = color;
|
||||||
|
|
||||||
if (!this.disabled) {
|
if (!this.disabled) {
|
||||||
if (active) {
|
if (isActive) {
|
||||||
style.backgroundColor = color;
|
style.backgroundColor = color;
|
||||||
} else {
|
} else {
|
||||||
style.color = color;
|
style.color = color;
|
||||||
@ -35,7 +35,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const titleColor = active ? this.activeColor : this.inactiveColor;
|
const titleColor = isActive ? this.activeColor : this.inactiveColor;
|
||||||
if (titleColor) {
|
if (titleColor) {
|
||||||
style.color = titleColor;
|
style.color = titleColor;
|
||||||
}
|
}
|
||||||
@ -64,9 +64,9 @@ export default {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
role="tab"
|
role="tab"
|
||||||
aria-selected={this.active}
|
aria-selected={this.isActive}
|
||||||
class={bem({
|
class={bem({
|
||||||
active: this.active,
|
active: this.isActive,
|
||||||
disabled: this.disabled,
|
disabled: this.disabled,
|
||||||
complete: !this.ellipsis
|
complete: !this.ellipsis
|
||||||
})}
|
})}
|
||||||
|
@ -73,7 +73,7 @@ export default createComponent({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
position: '',
|
position: '',
|
||||||
curActive: null,
|
currentIndex: null,
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
backgroundColor: this.color
|
backgroundColor: this.color
|
||||||
}
|
}
|
||||||
@ -108,13 +108,21 @@ export default createComponent({
|
|||||||
borderColor: this.color,
|
borderColor: this.color,
|
||||||
background: this.background
|
background: this.background
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
currentName() {
|
||||||
|
const activeTab = this.children[this.currentIndex];
|
||||||
|
|
||||||
|
if (activeTab) {
|
||||||
|
return activeTab.computedName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
active(val) {
|
active(name) {
|
||||||
if (val !== this.curActive) {
|
if (name !== this.currentName) {
|
||||||
this.correctActive(val);
|
this.setCurrentIndexByName(name);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -123,12 +131,12 @@ export default createComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
children() {
|
children() {
|
||||||
this.correctActive(this.curActive || this.active);
|
this.setCurrentIndexByName(this.currentName || this.active);
|
||||||
this.scrollIntoView();
|
this.scrollIntoView();
|
||||||
this.setLine();
|
this.setLine();
|
||||||
},
|
},
|
||||||
|
|
||||||
curActive() {
|
currentIndex() {
|
||||||
this.scrollIntoView();
|
this.scrollIntoView();
|
||||||
this.setLine();
|
this.setLine();
|
||||||
|
|
||||||
@ -201,11 +209,11 @@ export default createComponent({
|
|||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const { titles } = this.$refs;
|
const { titles } = this.$refs;
|
||||||
|
|
||||||
if (!titles || !titles[this.curActive] || this.type !== 'line') {
|
if (!titles || !titles[this.currentIndex] || this.type !== 'line') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = titles[this.curActive].$el;
|
const title = titles[this.currentIndex].$el;
|
||||||
const { lineWidth, lineHeight } = this;
|
const { lineWidth, lineHeight } = this;
|
||||||
const width = isDef(lineWidth) ? lineWidth : title.offsetWidth / 2;
|
const width = isDef(lineWidth) ? lineWidth : title.offsetWidth / 2;
|
||||||
const left = title.offsetLeft + title.offsetWidth / 2;
|
const left = title.offsetLeft + title.offsetWidth / 2;
|
||||||
@ -230,47 +238,47 @@ export default createComponent({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// correct the value of active
|
// correct the index of active tab
|
||||||
correctActive(active) {
|
setCurrentIndexByName(name) {
|
||||||
active = +active;
|
const matched = this.children.filter(tab => tab.computedName === name);
|
||||||
const exist = this.children.some(tab => tab.index === active);
|
const defaultIndex = (this.children[0] || {}).index || 0;
|
||||||
const defaultActive = (this.children[0] || {}).index || 0;
|
this.setCurrentIndex(matched.length ? matched[0].index : defaultIndex);
|
||||||
this.setCurActive(exist ? active : defaultActive);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setCurActive(active) {
|
setCurrentIndex(currentIndex) {
|
||||||
active = this.findAvailableTab(active, active < this.curActive);
|
currentIndex = this.findAvailableTab(currentIndex);
|
||||||
if (isDef(active) && active !== this.curActive) {
|
|
||||||
this.$emit('input', active);
|
|
||||||
|
|
||||||
if (this.curActive !== null) {
|
if (isDef(currentIndex) && currentIndex !== this.currentIndex) {
|
||||||
this.$emit('change', active, this.children[active].title);
|
const shouldEmitChange = this.currentIndex !== null;
|
||||||
|
this.currentIndex = currentIndex;
|
||||||
|
this.$emit('input', this.currentName);
|
||||||
|
|
||||||
|
if (shouldEmitChange) {
|
||||||
|
this.$emit('change', this.currentName, this.children[currentIndex].title);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.curActive = active;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
findAvailableTab(active, reverse) {
|
findAvailableTab(index) {
|
||||||
const diff = reverse ? -1 : 1;
|
const diff = index < this.currentIndex ? -1 : 1;
|
||||||
let index = active;
|
|
||||||
|
|
||||||
while (index >= 0 && index < this.children.length) {
|
while (index >= 0 && index < this.children.length) {
|
||||||
if (!this.children[index].disabled) {
|
if (!this.children[index].disabled) {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
index += diff;
|
index += diff;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// emit event when clicked
|
// emit event when clicked
|
||||||
onClick(index) {
|
onClick(index) {
|
||||||
const { title, disabled } = this.children[index];
|
const { title, disabled, name } = this.children[index];
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
this.$emit('disabled', index, title);
|
this.$emit('disabled', name, title);
|
||||||
} else {
|
} else {
|
||||||
this.setCurActive(index);
|
this.setCurrentIndex(index);
|
||||||
this.$emit('click', index, title);
|
this.$emit('click', name, title);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -278,12 +286,12 @@ export default createComponent({
|
|||||||
scrollIntoView(immediate) {
|
scrollIntoView(immediate) {
|
||||||
const { titles } = this.$refs;
|
const { titles } = this.$refs;
|
||||||
|
|
||||||
if (!this.scrollable || !titles || !titles[this.curActive]) {
|
if (!this.scrollable || !titles || !titles[this.currentIndex]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { nav } = this.$refs;
|
const { nav } = this.$refs;
|
||||||
const title = titles[this.curActive].$el;
|
const title = titles[this.currentIndex].$el;
|
||||||
const to = title.offsetLeft - (nav.offsetWidth - title.offsetWidth) / 2;
|
const to = title.offsetLeft - (nav.offsetWidth - title.offsetWidth) / 2;
|
||||||
|
|
||||||
scrollLeftTo(nav, to, immediate ? 0 : this.duration);
|
scrollLeftTo(nav, to, immediate ? 0 : this.duration);
|
||||||
@ -307,7 +315,7 @@ export default createComponent({
|
|||||||
type={type}
|
type={type}
|
||||||
title={item.title}
|
title={item.title}
|
||||||
color={this.color}
|
color={this.color}
|
||||||
active={index === this.curActive}
|
isActive={index === this.currentIndex}
|
||||||
ellipsis={ellipsis}
|
ellipsis={ellipsis}
|
||||||
disabled={item.disabled}
|
disabled={item.disabled}
|
||||||
scrollable={scrollable}
|
scrollable={scrollable}
|
||||||
@ -339,11 +347,11 @@ export default createComponent({
|
|||||||
</div>
|
</div>
|
||||||
<Content
|
<Content
|
||||||
count={this.children.length}
|
count={this.children.length}
|
||||||
active={this.curActive}
|
|
||||||
animated={animated}
|
animated={animated}
|
||||||
duration={this.duration}
|
duration={this.duration}
|
||||||
swipeable={this.swipeable}
|
swipeable={this.swipeable}
|
||||||
onChange={this.setCurActive}
|
currentIndex={this.currentIndex}
|
||||||
|
onChange={this.setCurrentIndex}
|
||||||
>
|
>
|
||||||
{this.slots()}
|
{this.slots()}
|
||||||
</Content>
|
</Content>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user