[new feature] Tab: add name prop (#3762)
This commit is contained in:
+27
-6
@@ -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
|
||||
|
||||
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
|
||||
export default {
|
||||
methods: {
|
||||
onClickDisabled(index, title) {
|
||||
onClickDisabled(name, title) {
|
||||
this.$toast(title + ' is disabled');
|
||||
}
|
||||
}
|
||||
@@ -91,7 +111,7 @@ Tabs styled as cards.
|
||||
```javascript
|
||||
export default {
|
||||
methods: {
|
||||
onClick(index, title) {
|
||||
onClick(name, 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 |
|
||||
|------|------|------|------|
|
||||
| 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` |
|
||||
| duration | Toggle tab's animation time | `Number` | `0.3` | - |
|
||||
| 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 |
|
||||
|------|------|------|------|
|
||||
| name | Identifier | `String | Number` | Index of tab |
|
||||
| title | Title | `String` | - |
|
||||
| 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 |
|
||||
|------|------|------|
|
||||
| click | Triggered when click tab | index:index of current tab,title: tab title |
|
||||
| change | Triggered when active tab changed | index:index of current tab,title: tab title |
|
||||
| disabled | Triggered when click disabled 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 | name:name 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 } |
|
||||
|
||||
+33
-10
@@ -12,7 +12,7 @@ Vue.use(Tab).use(Tabs);
|
||||
|
||||
### 基础用法
|
||||
|
||||
默认情况下启用第一个标签,可以通过`v-model`绑定当前激活的标签索引
|
||||
通过`v-model`绑定当前激活标签对应的索引值,默认情况下启用第一个标签
|
||||
|
||||
```html
|
||||
<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
|
||||
<van-tabs>
|
||||
@@ -60,8 +82,8 @@ export default {
|
||||
```javascript
|
||||
export default {
|
||||
methods: {
|
||||
onClickDisabled(index, title) {
|
||||
this.$toast(title + '已被禁用');
|
||||
onClickDisabled(name, title) {
|
||||
this.$toast(name + '已被禁用');
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -93,7 +115,7 @@ export default {
|
||||
```javascript
|
||||
export default {
|
||||
methods: {
|
||||
onClick(index, title) {
|
||||
onClick(name, title) {
|
||||
this.$toast(title);
|
||||
}
|
||||
}
|
||||
@@ -157,7 +179,7 @@ export default {
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
|------|------|------|------|------|
|
||||
| v-model | 当前标签的索引 | `String` `Number` | `0` | - |
|
||||
| v-model | 绑定当前选中标签的标识符 | `String | Number` | `0` | - |
|
||||
| type | 样式类型,可选值为`card` | `String` | `line` | - |
|
||||
| duration | 动画时间,单位秒 | `Number` | `0.3` | - |
|
||||
| background | 标签栏背景色 | `String` | `white` | 1.6.5 |
|
||||
@@ -179,6 +201,7 @@ export default {
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
|------|------|------|------|------|
|
||||
| name | 标签名称,作为匹配的标识符 | `String | Number` | 标签的索引值 | 2.0.6 |
|
||||
| title | 标题 | `String` | - | - |
|
||||
| disabled | 是否禁用标签 | `Boolean` | `false` | - |
|
||||
|
||||
@@ -200,7 +223,7 @@ export default {
|
||||
|
||||
| 事件名 | 说明 | 回调参数 |
|
||||
|------|------|------|
|
||||
| click | 点击标签时触发 | index:标签索引,title:标题 |
|
||||
| change | 当前激活的标签改变时触发 | index:标签索引,title:标题 |
|
||||
| disabled | 点击被禁用的标签时触发 | index:标签索引,title:标题 |
|
||||
| click | 点击标签时触发 | name:标签标识符,title:标题 |
|
||||
| change | 当前激活的标签改变时触发 | name:标签标识符,title:标题 |
|
||||
| disabled | 点击被禁用的标签时触发 | name:标签标识符,title:标题 |
|
||||
| scroll | 滚动时触发,仅在 sticky 模式下生效 | { scrollTop: 距离顶部位置, isFixed: 是否吸顶 } |
|
||||
|
||||
+30
-8
@@ -12,8 +12,31 @@
|
||||
</van-tabs>
|
||||
</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')">
|
||||
<van-tabs @scroll="onScroll">
|
||||
<van-tabs>
|
||||
<van-tab
|
||||
v-for="index in 8"
|
||||
:title="$t('tab') + index"
|
||||
@@ -124,7 +147,7 @@ export default {
|
||||
i18n: {
|
||||
'zh-CN': {
|
||||
tab: '标签 ',
|
||||
title2: '横向滚动',
|
||||
title2: '标签栏滚动',
|
||||
title3: '禁用标签',
|
||||
title4: '样式风格',
|
||||
title5: '点击事件',
|
||||
@@ -132,7 +155,8 @@ export default {
|
||||
title7: '自定义标签',
|
||||
title8: '切换动画',
|
||||
title9: '滑动切换',
|
||||
disabled: ' 已被禁用'
|
||||
disabled: ' 已被禁用',
|
||||
matchByName: '通过名称匹配'
|
||||
},
|
||||
'en-US': {
|
||||
tab: 'Tab ',
|
||||
@@ -145,13 +169,15 @@ export default {
|
||||
title7: 'Custom Tab',
|
||||
title8: 'Switch Animation',
|
||||
title9: 'Swipeable',
|
||||
disabled: ' is disabled'
|
||||
disabled: ' is disabled',
|
||||
matchByName: 'Match By Name'
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
active: 2,
|
||||
activeName: 'b',
|
||||
tabs: [1, 2, 3, 4]
|
||||
};
|
||||
},
|
||||
@@ -163,10 +189,6 @@ export default {
|
||||
|
||||
onClick(index, title) {
|
||||
this.$toast(title);
|
||||
},
|
||||
|
||||
onScroll(e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+13
-8
@@ -8,6 +8,7 @@ export default createComponent({
|
||||
mixins: [ChildrenMixin('vanTabs')],
|
||||
|
||||
props: {
|
||||
name: [String, Number],
|
||||
title: String,
|
||||
disabled: Boolean
|
||||
},
|
||||
@@ -19,14 +20,18 @@ export default createComponent({
|
||||
},
|
||||
|
||||
computed: {
|
||||
selected() {
|
||||
return this.index === this.parent.curActive;
|
||||
computedName() {
|
||||
return this.name || this.index;
|
||||
},
|
||||
|
||||
isActive() {
|
||||
return this.computedName === this.parent.currentName;
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
'parent.curActive'() {
|
||||
this.inited = this.inited || this.selected;
|
||||
'parent.currentIndex'() {
|
||||
this.inited = this.inited || this.isActive;
|
||||
},
|
||||
|
||||
title() {
|
||||
@@ -41,7 +46,7 @@ export default createComponent({
|
||||
},
|
||||
|
||||
render(h) {
|
||||
const { slots, selected } = this;
|
||||
const { slots, isActive } = this;
|
||||
const shouldRender = this.inited || !this.parent.lazyRender;
|
||||
const Content = [shouldRender ? slots() : h()];
|
||||
|
||||
@@ -53,8 +58,8 @@ export default createComponent({
|
||||
return (
|
||||
<div
|
||||
role="tabpanel"
|
||||
aria-hidden={!selected}
|
||||
class={bem('pane-wrapper', { inactive: !selected })}
|
||||
aria-hidden={!isActive}
|
||||
class={bem('pane-wrapper', { inactive: !isActive })}
|
||||
>
|
||||
<div class={bem('pane')}>{Content}</div>
|
||||
</div>
|
||||
@@ -62,7 +67,7 @@ export default createComponent({
|
||||
}
|
||||
|
||||
return (
|
||||
<div vShow={selected} role="tabpanel" class={bem('pane')}>
|
||||
<div vShow={isActive} role="tabpanel" class={bem('pane')}>
|
||||
{Content}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -29,6 +29,29 @@ exports[`renders demo correctly 1`] = `
|
||||
</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 class="van-tabs van-tabs--line">
|
||||
<div class="van-tabs__wrap van-tabs__wrap--scrollable van-hairline--top-bottom">
|
||||
|
||||
@@ -136,6 +136,28 @@ exports[`lazy render 2`] = `
|
||||
</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`] = `
|
||||
<div class="van-tabs van-tabs--line">
|
||||
<div class="van-tabs__wrap van-hairline--top-bottom">
|
||||
|
||||
@@ -145,3 +145,38 @@ test('border props', async () => {
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user