From 48c40ffa0a9ed64715d5e786441ceb3112eeeea8 Mon Sep 17 00:00:00 2001 From: Jikkai Xiao Date: Mon, 21 May 2018 19:10:49 +0800 Subject: [PATCH] Tabs: add before-leave hook (#11259) * Tabs: add before-leave hook * Tabs: update tabs.d.ts --- examples/docs/en-US/tabs.md | 1 + examples/docs/es/tabs.md | 1 + examples/docs/zh-CN/tabs.md | 1 + packages/tabs/src/tabs.vue | 21 ++++++++++++-- test/unit/specs/tabs.spec.js | 55 ++++++++++++++++++++++++++++++++++++ types/tabs.d.ts | 3 ++ 6 files changed, 79 insertions(+), 3 deletions(-) diff --git a/examples/docs/en-US/tabs.md b/examples/docs/en-US/tabs.md index d078be7d9..e96079956 100644 --- a/examples/docs/en-US/tabs.md +++ b/examples/docs/en-US/tabs.md @@ -376,6 +376,7 @@ Only card type Tabs support addable & closeable. | editable | whether Tab is addable and closable | boolean | — | false | | value | name of the selected tab | string | — | name of first tab | | tab-position | position of tabs | string | top/right/bottom/left | top | +| before-leave | hook function before switching tab. If `false` is returned or a `Promise` is returned and then is rejected, switching will be prevented | function | — | — | ### Tabs Events | Event Name | Description | Parameters | diff --git a/examples/docs/es/tabs.md b/examples/docs/es/tabs.md index cc7674754..fab0e2826 100644 --- a/examples/docs/es/tabs.md +++ b/examples/docs/es/tabs.md @@ -376,6 +376,7 @@ Solo las pestañas de tipo tarjeta soportan adición y cierre. | editable | si la Pestaña es añadible y cerrable | boolean | — | false | | value | nombre de la pestaña seleccionada | string | — | nombre de la primer pestaña | | tab-position | posición de tabulación | string | top/right/bottom/left | top | +| before-leave | hook function before switching tab. If `false` is returned or a `Promise` is returned and then is rejected, switching will be prevented | function | — | — | ### Eventos de Pestañas | Nombre de Evento | Descripción | Parámetros | diff --git a/examples/docs/zh-CN/tabs.md b/examples/docs/zh-CN/tabs.md index a1b9795d2..26ecc4394 100644 --- a/examples/docs/zh-CN/tabs.md +++ b/examples/docs/zh-CN/tabs.md @@ -374,6 +374,7 @@ | editable | 标签是否同时可增加和关闭 | boolean | — | false | | value | 绑定值,选中选项卡的 name | string | — | 第一个选项卡的 name | | tab-position | 选项卡所在位置 | string | top/right/bottom/left | top | +| before-leave | 切换标签之前的钩子,若返回 false 或者返回 Promise 且被 reject,则阻止切换。 | function | — | — | ### Tabs Events | 事件名称 | 说明 | 回调参数 | diff --git a/packages/tabs/src/tabs.vue b/packages/tabs/src/tabs.vue index 7dd20edde..c1e348cb5 100644 --- a/packages/tabs/src/tabs.vue +++ b/packages/tabs/src/tabs.vue @@ -18,7 +18,8 @@ tabPosition: { type: String, default: 'top' - } + }, + beforeLeave: Function }, provide() { @@ -67,8 +68,22 @@ this.$emit('tab-add'); }, setCurrentName(value) { - this.currentName = value; - this.$emit('input', value); + const changeCurrentName = () => { + this.currentName = value; + this.$emit('input', value); + }; + if (this.currentName !== value && this.beforeLeave) { + const before = this.beforeLeave(); + if (before && before.then) { + before.then(() => { + changeCurrentName(); + }); + } else if (before !== false) { + changeCurrentName(); + } + } else { + changeCurrentName(); + } }, addPanes(item) { const index = this.$slots.default.filter(item => { diff --git a/test/unit/specs/tabs.spec.js b/test/unit/specs/tabs.spec.js index 95afa5906..a83414ffe 100644 --- a/test/unit/specs/tabs.spec.js +++ b/test/unit/specs/tabs.spec.js @@ -2,6 +2,20 @@ import { createVue, destroyVM } from '../util'; describe('Tabs', () => { let vm; + let hasPromise = true; + before(() => { + if (!window.Promise) { + hasPromise = false; + window.Promise = require('es6-promise').Promise; + } + }); + + after(() => { + if (!hasPromise) { + window.Promise = undefined; + } + }); + afterEach(() => { destroyVM(vm); }); @@ -457,4 +471,45 @@ describe('Tabs', () => { }); }, 100); }); + it('before leave', done => { + vm = createVue({ + template: ` + + A + B + C + D + + `, + data() { + return { + activeName: 'tab-B' + }; + }, + methods: { + beforeLeave() { + return new window.Promise((resolve, reject) => { + reject(); + }); + } + } + }, true); + setTimeout(_ => { + const paneList = vm.$el.querySelector('.el-tabs__content').children; + const tabList = vm.$refs.tabs.$refs.nav.$refs.tabs; + + expect(tabList[1].classList.contains('is-active')).to.be.true; + expect(paneList[1].style.display).to.not.ok; + + tabList[3].click(); + vm.$nextTick(_ => { + setTimeout(() => { + expect(tabList[1].classList.contains('is-active')).to.be.true; + expect(paneList[1].style.display).to.not.ok; + expect(vm.activeName === 'tab-B'); + done(); + }, 200); + }); + }, 100); + }); }); diff --git a/types/tabs.d.ts b/types/tabs.d.ts index 85351f357..d583a8058 100644 --- a/types/tabs.d.ts +++ b/types/tabs.d.ts @@ -22,4 +22,7 @@ export declare class ElTabs extends ElementUIComponent { /** Position of tabs */ tabPosition: TabPosition + + /** Hook function before switching tab. If false or a Promise is returned and then is rejected, switching will be prevented */ + beforeLeave: () => boolean | Promise }