# 组件使用
## tab 标签页
### 介绍
- `Tab`标签页。
### 代码演示
#### 基础用法
通过 `v-model` 绑定当前激活标签对应的索引值,默认情况下启用第一个标签。
```html
<em-tabs v-model="active">
<em-tab title="标签 1">内容 1</em-tab>
<em-tab title="标签 2">内容 2</em-tab>
<em-tab title="标签 3">内容 3</em-tab>
<em-tab title="标签 4">内容 4</em-tab>
</em-tabs>
```
::: ifdef M83
```js
export default {
data() {
return {
active: 0
};
}
};
```
::: endif
::: ifdef M84
```js
import { ref } from 'vue';
const active = ref(0);
```
::: endif
#### 子级扩展
通过`sub-tabs`可设置标签的默认子级扩展,通过`@subTabClick`设置扩展选项点击事项。
也可以通过名为`subtab`的插槽设置自定义的子级扩展内容。
```html
<em-tabs v-model="active">
<em-tab title="选中项目" :sub-tabs="subTabs" @subTabClick="subTabClick">
<div class="tab-content">默认的横向扩展</div>
</em-tab>
<em-tab title="标签 2">
<template v-slot:subtab>
<div class="sub-content">自定义子级扩展内容</div>
</template>
<div class="tab-content">内容 2</div>
</em-tab>
</em-tabs>
```
::: ifdef M83
```js
export default {
data() {
return {
active: 0,
subTabs: [
{
text: '选项1',
value: 1,
checked: true
},
{
text: '选项2',
value: 2
},
{
text: '选项3',
value: 3
},
{
text: '选项4',
value: 4
}
]
};
},
methods: {
subTabClick(item, index) {
Toast(item.text);
}
}
};
```
::: endif
::: ifdef M84
```js
import { ref } from 'vue';
const active = ref(0);
const subTabs = [
{
text: '选项1',
value: 1,
checked: true
},
{
text: '选项2',
value: 2
},
{
text: '选项3',
value: 3
},
{
text: '选项4',
value: 4
}
];
const subTabClick = (item, index) => {
Toast(item.text);
};
```
::: endif
#### 下拉
通过`isDropdown`可设置标签是否可下拉。
组件提供两种默认的子级扩展,可通过`sub-direction`设置展示为横向`horizontal`或纵向`vertical`。
```html
<em-tabs v-model="active">
<em-tab title="选中项目" :sub-tabs="subTabs" :isDropdown="true" sub-direction="vertical" @subTabClick="subTabClick">
<div class="tab-content-down">默认的纵向扩展</div>
</em-tab>
<em-tab title="标签 2" :sub-tabs="subTabs" :isDropdown="true" sub-direction="horizontal" @subTabClick="subTabClick">
<div class="tab-content-down">默认的横向扩展</div>
</em-tab>
<em-tab title="标签 3" :isDropdown="true">
<template v-slot:subtab>
<div class="sub-content">自定义子级扩展内容</div>
</template>
<div class="tab-content-down">内容 3</div>
</em-tab>
</em-tabs>
```
::: ifdef M83
```js
export default {
data() {
return {
active: 0,
subTabs: [
{
text: '选项1',
value: 1,
checked: true
},
{
text: '选项2',
value: 2
},
{
text: '选项3',
value: 3
},
{
text: '选项4',
value: 4
}
]
};
},
methods: {
subTabClick(item, index) {
Toast(item.text);
}
}
};
```
::: endif
::: ifdef M84
```js
import { ref } from 'vue';
const active = ref(0);
const subTabs = [
{
text: '选项1',
value: 1,
checked: true
},
{
text: '选项2',
value: 2
},
{
text: '选项3',
value: 3
},
{
text: '选项4',
value: 4
}
];
const subTabClick = (item, index) => {
Toast(item.text);
};
```
::: endif
#### 同级扩展
标签数量较多时,通过`putaway`可设置同级扩展。
```html
<em-tabs v-model="active" :putaway="true">
<em-tab v-for="item in [1,2,3,4,5,6,7,8,9]" :key="item" :title="`标签 ${item}`">
<div class="tab-content">内容 {{item}}</div>
</em-tab>
</em-tabs>
```
::: ifdef M83
```js
export default {
data() {
return {
active: 0
};
}
};
```
::: endif
::: ifdef M84
```js
import { ref } from 'vue';
const active = ref(0);
```
::: endif
#### 通过名称匹配
在标签指定 `name` 属性的情况下,`v-model` 的值为当前标签的 `name`(此时无法通过索引值来匹配标签)。
```html
<em-tabs v-model="activeName">
<em-tab title="标签 1" name="a">内容 1</em-tab>
<em-tab title="标签 2" name="b">内容 2</em-tab>
<em-tab title="标签 3" name="c">内容 3</em-tab>
</em-tabs>
```
::: ifdef M83
```js
export default {
data() {
return {
activeName: 'a'
};
}
};
```
::: endif
::: ifdef M84
```js
import { ref } from 'vue';
const activeName = ref('a');
```
::: endif
#### 标签栏滚动
标签数量超过 `5` 个时,标签栏可以在水平方向上滚动,切换时会自动将当前标签居中。
```html
<em-tabs>
<em-tab v-for="index in 8" :title="'标签 ' + index">内容 {{ index }}</em-tab>
</em-tabs>
```
#### 禁用标签
设置 `disabled` 属性即可禁用标签,如果需要监听禁用标签的点击事件,可以在 `em-tabs` 上监听`disabled` 事件。
```html
<em-tabs @disabled="onClickDisabled">
<em-tab title="标签 1">内容 1</em-tab>
<em-tab title="标签 2" disabled>内容 2</em-tab>
<em-tab title="标签 3">内容 3</em-tab>
</em-tabs>
```
::: ifdef M83
```js
export default {
methods: {
onClickDisabled(name, title) {
Toast(name + '已被禁用');
}
}
};
```
::: endif
::: ifdef M84
```js
const onClickDisabled = (name, title) => {
Toast(name + '已被禁用');
};
```
::: endif
#### 样式风格
`Tab` 支持两种样式风格:`line` 和`card`,默认为 `line` 样式,可以通过 `type` 属性切换样式风格。
```html
<em-tabs type="card">
<em-tab title="标签 1">内容 1</em-tab>
<em-tab title="标签 2">内容 2</em-tab>
<em-tab title="标签 3">内容 3</em-tab>
</em-tabs>
```
#### 点击事件
可以在 `em-tabs` 上绑定 `click` 事件,事件传参为标签对应的标识符和标题。
```html
<em-tabs @click="onClick">
<em-tab title="标签 1">内容 1</em-tab>
<em-tab title="标签 2">内容 2</em-tab>
</em-tabs>
```
::: ifdef M83
```js
export default {
methods: {
onClick(name, title) {
Toast(title);
}
}
};
```
::: endif
::: ifdef M84
```js
const onClick = (name, title) => {
Toast(title);
};
```
::: endif
#### 粘性布局
通过 `sticky` 属性可以开启粘性布局,粘性布局下,标签页滚动到顶部时会自动吸顶。
**TIP:** 使用粘性布局时,微信小程序中,页面上需要添加`onPageScroll`函数用于监听页面滚动
```html
<em-tabs v-model="active" sticky>
<em-tab v-for="index in 4" :title="'选项 ' + index">内容 {{ index }}</em-tab>
</em-tabs>
```
#### 切换动画
通过 `animated` 属性可以开启切换标签内容时的转场动画。
```html
<em-tabs v-model="active" animated>
<em-tab v-for="index in 4" :title="'选项 ' + index">内容 {{ index }}</em-tab>
</em-tabs>
```
#### 滑动切换
通过 `swipeable` 属性可以开启滑动切换标签页。
```html
<em-tabs v-model="active" swipeable>
<em-tab v-for="index in 4" :title="'选项 ' + index">内容 {{ index }}</em-tab>
</em-tabs>
```
#### 滚动导航
通过 `scrollspy` 属性可以开启滚动导航模式,该模式下,内容将会平铺展示。
**TIP:** 使用粘性布局时,微信小程序中,页面上需要添加`onPageScroll`函数用于监听页面滚动。
tab 组件的父级容器及祖先容器的`overflow`只能是`visible`。
```html
<em-tabs v-model="active" scrollspy sticky>
<em-tab v-for="index in 8" :title="'选项 ' + index">内容 {{ index }}</em-tab>
</em-tabs>
```
#### 异步切换
通过 `before-change` 属性可以在切换标签前执行特定的逻辑。
```html
<em-tabs :before-change="beforeChange">
<em-tab v-for="index in 4" :title="'选项 ' + index">内容 {{ index }}</em-tab>
</em-tabs>
```
::: ifdef M83
```js
export default {
methods: {
beforeChange(index) {
// 返回 false 表示阻止此次切换
if (index === 1) {
return false;
}
// 返回 Promise 来执行异步逻辑
return new Promise((resolve) => {
// 在 resolve 函数中返回 true 或 false
resolve(index !== 3);
});
}
}
};
```
::: endif
::: ifdef M84
```js
const beforeChange = (index) => {
// 返回 false 表示阻止此次切换
if (index === 1) {
return false;
}
// 返回 Promise 来执行异步逻辑
return new Promise((resolve) => {
// 在 resolve 函数中返回 true 或 false
resolve(index !== 3);
});
};
```
::: endif
### API
#### Tabs Props
| 参数 | 说明 | 类型 | 默认值 |
| :--------------------------------------------------------------------------- | :------------------------------------------------------------------- | :-------------------------- | :-------- |
| v-model ::: ifdef M83 (value) ::: endif ::: ifdef M84 (modelValue) ::: endif | 绑定当前选中标签的标识符 | number / string | `0` |
| type | 样式风格类型,可选值为 `card` | string | `line` |
| color | 标签主题色 | string | `#2e6be5` |
| background | 标签栏背景色 | string | `white` |
| duration | 动画时间,单位秒 | number / string | `0.3` |
| line-width | 底部条宽度,默认单位`px` | number / string | `30px` |
| line-height | 底部条高度,默认单位`px` | number / string | `3px` |
| line-skew | 是否开启底部条两端倾斜角度效果 | boolean | `true` |
| animated | 是否开启切换标签内容时的转场动画 | boolean | `false` |
| border | 是否显示标签栏外边框,仅在 `type="line"`时有效 | boolean | `true` |
| ellipsis | 是否省略过长的标题文字 | boolean | `true` |
| sticky | 是否使用粘性定位布局 | boolean | `false` |
| scrollspy | 是否使用滚动导航 | boolean | `false` |
| swipeable | 是否开启手势滑动切换 | boolean | `false` |
| lazy-render | 是否开启延迟渲染(首次切换到标签时才触发内容渲染) | boolean | `true` |
| offset-top | 粘性定位布局下与顶部的最小距离,支持 `px` `vw` `rem` 单位,默认 `px` | number / string | `0` |
| swipe-threshold | 滚动阈值,标签数量超过阈值时开始横向滚动 | number / string | `5` |
| title-active-color | 标题选中态颜色 | string | - |
| title-inactive-color | 标题默认态颜色 | string | - |
| before-change | 切换标签前的回调函数,返回 `false` 可阻止切换,支持返回 `Promise` | (name) => boolean / Promise | - |
| putaway | 标签数过多时是否展示同级扩展 | boolean | `false` |
| shrink | 标签是否开启左对齐 | boolean | `false` |
| pop-height `v8.3.7` | 自定义下拉弹窗的高度,单位为`px` | string/number | - |
#### Tab Props
| 参数 | 说明 | 类型 | 默认值 |
| :----------- | :-------------------------------------------------------------------------------------------- | :-------------- | :----------- |
| title | 标题 | string | - |
| disabled | 是否禁用标签 | boolean | `false` |
| dot | 是否在标题右上角显示小红点 | boolean | `false` |
| badge | 图标右上角徽标的内容 | number / string | - |
| name | 标签名称,作为匹配的标识符 | number / string | 标签的索引值 |
| url | 点击后跳转的链接地址 | string | - |
| to | 点击后跳转的目标路由对象,同 `vue-router` 的 `to` 属性,仅支持`path` `query` `replace` `hash` | string / object | - |
| replace | 是否在跳转时替换当前页面历史 | boolean | `false` |
| title-style | 自定义标题样式 | any | - |
| subTabs | 子级扩展列表 | array | - |
| subDirection | 子级扩展排列方向,可选值:` horizontal``vertical ` | string | `horizontal` |
| isDropdown | 是否下拉 | boolean | `false` |
| overlay | 下拉时是否需要遮罩 | boolean | `true` |
#### Tab subTab 数据格式
| 参数 | 说明 | 类型 |
| :------ | :------------------------------------------------------------------------- | :------ |
| text | 选项文字 | string |
| value | 选项值 | string |
| checked | 是否已选中,初始化时可通过该参数设置默认选中项,注意:默认子级扩展都是单选 | boolean |
#### Tabs Events
| 事件名 | 说明 | 回调参数 |
| :------------- | :----------------------------------------------- | :------------------------------------------------- |
| click | 点击标签时触发 | `name`:标识符,`title`:标题 |
| change | 当前激活的标签改变时触发 | `name`:标识符,`title`:标题 |
| disabled | 点击被禁用的标签时触发 | `name`:标识符,`title`:标题 |
| rendered | 标签内容首次渲染时触发(仅在开启延迟渲染后触发) | `name`:标识符,`title`:标题 |
| scroll | 滚动时触发,仅在 `sticky` 模式下生效 | { `scrollTop`: 距离顶部位置, `isFixed`: 是否吸顶 } |
| load `v8.3.14` | mounted 中触发 | - |
#### Tab Events
| 事件名 | 说明 | 回调参数 |
| :------------- | :------------------------------------- | :---------------------------------- |
| subTabClick | 使用默认子级扩展时,点击扩展选项的事件 | `item`:选中项,`index`:选中项索引 |
| load `v8.3.14` | mounted 中触发 | - |
#### Tabs 方法
通过 ref 可以获取到 Tabs 实例并调用实例方法,详见组件实例方法
| 方法名 | 说明 | 参数 | 返回值 |
| :----- | :------------------------------------------- | :--- | :----- |
| resize | 外层元素大小变化后,可以调用此方法来触发重绘 | - | `void` |
#### Tab 方法
通过 ref 可以获取到 Tab 实例并调用实例方法,详见组件实例方法
| 方法名 | 说明 | 参数 | 返回值 |
| :--------- | :----------------------------------- | :--- | :----- |
| triggerPop | 使用下拉时,可通过此方法切换下拉状态 | - | `void` |
#### Tabs Slots
| 名称 | 说明 |
| :------- | :----------- |
| navLeft | 标题左侧内容 |
| navRight | 标题右侧内容 |
#### Tab Slots
| 名称 | 说明 |
| :------ | :------------- |
| default | 标签页内容 |
| subtab | 自定义子级扩展 |
::: ifdef M83
<iframe
src="//app.epoint.com.cn/m8mpdoc/showcase/index.html#/modules/m8showcase/examples/em-tab"
frameborder=0
allowfullscreen class="ui-showcase-iframe">
</iframe>
::: endif
::: ifdef M84
<iframe
src="//app.epoint.com.cn/m8mpdoc/showcase/m8.4/index.html#/modules/m8showcase/examples/em-tab"
frameborder=0
allowfullscreen class="ui-showcase-iframe">
</iframe>
::: endif
<style>
.ui-showcase-iframe {
position: fixed;
right: 3.5vw;
top: 17%;
width: 375px;
height: 75vh;
box-shadow: 0 0 12px 6px #eee;
border-radius: 15px;
}
.main .markdown-body {
padding: 45px;
width: calc(97vw - 661px);
}
</style>