diff --git a/packages/tab/README.md b/packages/tab/README.md
index be6b12ce..83201900 100644
--- a/packages/tab/README.md
+++ b/packages/tab/README.md
@@ -185,6 +185,49 @@ Page({
```
+### 异步切换
+
+通过 `before-change` 事件可以在切换标签前执行特定的逻辑,实现切换前校验、异步切换的目的
+
+```html
+
+ 内容 1
+ 内容 2
+ 内容 3
+ 内容 4
+
+```
+
+```js
+Page({
+ data: {
+ active: 1,
+ },
+
+ onChange(event) {
+ wx.showToast({
+ title: `切换到标签 ${event.detail.name}`,
+ icon: 'none',
+ });
+ },
+ onBeforeChange(event) {
+ const { callback, title } = event.detail;
+
+ wx.showModal({
+ title: '异步切换',
+ content: `确定要切换至 ${title} tab吗?`,
+ success: (res) => {
+ if (res.confirm) {
+ callback(true)
+ } else if (res.cancel) {
+ callback(false)
+ }
+ },
+ })
+ }
+});
+```
+
## API
### Tabs Props
@@ -208,6 +251,7 @@ Page({
| title-active-color | 标题选中态颜色 | _string_ | - |
| title-inactive-color | 标题默认态颜色 | _string_ | - |
| z-index | z-index 层级 | _number_ | `1` |
+| use-before-change `v1.10.10` | 是否开启切换前校验 | _boolean_ | `false` |
### Tab Props
@@ -238,18 +282,19 @@ Page({
| 事件名 | 说明 | 参数 |
| --- | --- | --- |
| bind:click | 点击标签时触发 | name:标签标识符,title:标题 |
+| bind:before-change `v1.10.10` | tab 切换前会触发,在回调函数中返回 `false` 可终止 tab 切换,绑定事件的同时需要将`use-before-change`属性设置为`true` | `event.detail.name`: 当前切换的 tab 标识符, `event.detail.title`: 当前切换的 tab 标题, `event.detail.index`: 当前切换的 tab 下标,`event.detail.callback`: 回调函数,调用`callback(false)`终止 tab 切换 |
| bind:change | 当前激活的标签改变时触发 | name:标签标识符,title:标题 |
| bind:disabled | 点击被禁用的标签时触发 | name:标签标识符,title:标题 |
| bind:scroll | 滚动时触发 | { scrollTop: 距离顶部位置, isFixed: 是否吸顶 } |
### 外部样式类
-| 类名 | 说明 |
-| ---------------- | ---------------- |
-| custom-class | 根节点样式类 |
-| nav-class | 标签栏样式类 |
-| tab-class | 标签样式类 |
-| tab-active-class | 标签激活态样式类 |
+| 类名 | 说明 |
+| ---------------- | ------------------ |
+| custom-class | 根节点样式类 |
+| nav-class | 标签栏样式类 |
+| tab-class | 标签样式类 |
+| tab-active-class | 标签激活态样式类 |
| wrap-class | 标签栏根节点样式类 |
### 方法
diff --git a/packages/tab/demo/index.ts b/packages/tab/demo/index.ts
index 8f126791..7b02b818 100644
--- a/packages/tab/demo/index.ts
+++ b/packages/tab/demo/index.ts
@@ -41,5 +41,20 @@ VantComponent({
icon: 'none',
});
},
+ onBeforeChange(event) {
+ const { callback, title } = event.detail;
+
+ wx.showModal({
+ title: '异步切换',
+ content: `确定要切换至 ${title} tab吗?`,
+ success: (res) => {
+ if (res.confirm) {
+ callback(true);
+ } else if (res.cancel) {
+ callback(false);
+ }
+ },
+ });
+ },
},
});
diff --git a/packages/tab/demo/index.wxml b/packages/tab/demo/index.wxml
index 67c12433..fc71dc70 100644
--- a/packages/tab/demo/index.wxml
+++ b/packages/tab/demo/index.wxml
@@ -147,3 +147,18 @@
+
+
+
+
+
+ {{ '内容' + item }}
+
+
+
+
+
diff --git a/packages/tab/test/__snapshots__/demo.spec.ts.snap b/packages/tab/test/__snapshots__/demo.spec.ts.snap
index d4fda650..3140df14 100644
--- a/packages/tab/test/__snapshots__/demo.spec.ts.snap
+++ b/packages/tab/test/__snapshots__/demo.spec.ts.snap
@@ -1548,5 +1548,165 @@ exports[`should render demo and match snapshot 1`] = `
+
+
+
+ 异步切换
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 标签 1
+
+
+
+
+
+
+ 标签 2
+
+
+
+
+
+
+ 标签 3
+
+
+
+
+
+
+ 标签 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 内容2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`;
diff --git a/packages/tabs/index.ts b/packages/tabs/index.ts
index 04e8177a..0af7cd7b 100644
--- a/packages/tabs/index.ts
+++ b/packages/tabs/index.ts
@@ -93,6 +93,10 @@ VantComponent({
type: Boolean,
value: true,
},
+ useBeforeChange: {
+ type: Boolean,
+ value: false,
+ },
},
data: {
@@ -134,17 +138,13 @@ VantComponent({
trigger(eventName: string, child?: TrivialInstance) {
const { currentIndex } = this.data;
- const currentChild = child || this.children[currentIndex];
+ const data = this.getChildData(currentIndex, child);
- if (!isDef(currentChild)) {
+ if (!isDef(data)) {
return;
}
- this.$emit(eventName, {
- index: currentChild.index,
- name: currentChild.getComputedName(),
- title: currentChild.data.title,
- });
+ this.$emit(eventName, data);
},
onTap(event: WechatMiniprogram.TouchEvent) {
@@ -153,12 +153,15 @@ VantComponent({
if (child.data.disabled) {
this.trigger('disabled', child);
- } else {
+ return;
+ }
+
+ this.onBeforeChange(index).then(() => {
this.setCurrentIndex(index);
nextTick(() => {
this.trigger('click');
});
- }
+ });
},
// correct the index of active tab
@@ -313,7 +316,7 @@ VantComponent({
if (direction === 'horizontal' && offsetX >= minSwipeDistance) {
const index = this.getAvaiableTab(deltaX);
if (index !== -1) {
- this.setCurrentIndex(index);
+ this.onBeforeChange(index).then(() => this.setCurrentIndex(index));
}
}
@@ -343,5 +346,32 @@ VantComponent({
return -1;
},
+ onBeforeChange(index: number): Promise {
+ const { useBeforeChange } = this.data;
+
+ if (!useBeforeChange) {
+ return Promise.resolve();
+ }
+
+ return new Promise((resolve, reject) => {
+ this.$emit('before-change', {
+ ...this.getChildData(index),
+ callback: (status) => (status ? resolve() : reject()),
+ });
+ });
+ },
+ getChildData(index: number, child?: TrivialInstance) {
+ const currentChild = child || this.children[index];
+
+ if (!isDef(currentChild)) {
+ return;
+ }
+
+ return {
+ index: currentChild.index,
+ name: currentChild.getComputedName(),
+ title: currentChild.data.title,
+ };
+ },
},
});