From 76522a173fa2b51b5ded6200577b7daf0acf892c Mon Sep 17 00:00:00 2001 From: landluck Date: Wed, 14 Dec 2022 10:24:32 +0800 Subject: [PATCH] feat(tab): add before-change event support (#5139) * feat(tab): add before-change event support * docs(tab): delete unnecessary content --- packages/tab/README.md | 57 ++++++- packages/tab/demo/index.ts | 15 ++ packages/tab/demo/index.wxml | 15 ++ .../tab/test/__snapshots__/demo.spec.ts.snap | 160 ++++++++++++++++++ packages/tabs/index.ts | 50 ++++-- 5 files changed, 281 insertions(+), 16 deletions(-) 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, + }; + }, }, });