瀏覽代碼

Tabs: add before-leave hook (#11259)

* Tabs: add before-leave hook

* Tabs: update tabs.d.ts
Jikkai Xiao 7 年之前
父節點
當前提交
48c40ffa0a
共有 6 個文件被更改,包括 79 次插入3 次删除
  1. 1 0
      examples/docs/en-US/tabs.md
  2. 1 0
      examples/docs/es/tabs.md
  3. 1 0
      examples/docs/zh-CN/tabs.md
  4. 18 3
      packages/tabs/src/tabs.vue
  5. 55 0
      test/unit/specs/tabs.spec.js
  6. 3 0
      types/tabs.d.ts

+ 1 - 0
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 |

+ 1 - 0
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                    |

+ 1 - 0
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
 | 事件名称 | 说明 | 回调参数 |

+ 18 - 3
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 => {

+ 55 - 0
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: `
+        <el-tabs ref="tabs" v-model="activeName" :before-leave="beforeLeave">
+          <el-tab-pane name="tab-A" label="用户管理">A</el-tab-pane>
+          <el-tab-pane name="tab-B" label="配置管理">B</el-tab-pane>
+          <el-tab-pane name="tab-C" label="角色管理">C</el-tab-pane>
+          <el-tab-pane name="tab-D" label="定时任务补偿">D</el-tab-pane>
+        </el-tabs>
+      `,
+      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);
+  });
 });

+ 3 - 0
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<any>
 }