浏览代码

MessageBox: add beforeClose

Leopoldthecoder 8 年之前
父节点
当前提交
35f102fa2c

+ 32 - 3
examples/docs/en-US/message-box.md

@@ -64,7 +64,21 @@
           message: 'This is a message',
           showCancelButton: true,
           confirmButtonText: 'OK',
-          cancelButtonText: 'Cancel'
+          cancelButtonText: 'Cancel',
+          beforeClose: (action, instance) => {
+            if (action === 'confirm') {
+              instance.confirmButtonLoading = true;
+              instance.confirmButtonText = 'Loading...';
+              setTimeout(() => {
+                instance.close();
+                setTimeout(() => {
+                  instance.confirmButtonLoading = false;
+                }, 300);
+              }, 3000);
+            } else {
+              instance.close();
+            }
+          }
         }).then(action => {
           setTimeout(() => {
             this.$message({
@@ -194,7 +208,7 @@ Prompt is used when user input is required.
 
 Can be customized to show various content.
 
-:::demo The three methods mentioned above are repackagings of the `$msgbox` method. This example calls `$msgbox` method directly using the `showCancelButton` attribute, which is used to indicate if a cancel button is displayed. Besides we can use `cancelButtonClass` to add a custom style and `cancelButtonText` to customize the button text. The confirm button also has these fields. A complete list of fields can be found at the end of this documentation.
+:::demo The three methods mentioned above are repackagings of the `$msgbox` method. This example calls `$msgbox` method directly using the `showCancelButton` attribute, which is used to indicate if a cancel button is displayed. Besides we can use `cancelButtonClass` to add a custom style and `cancelButtonText` to customize the button text (the confirm button also has these fields, and a complete list of fields can be found at the end of this documentation). This example also uses the `beforeClose` attribute. It is a method and will be triggered when the MessageBox instance will be closed, and its execution will stop the instance from closing. It has two parameters: `action` and `instance`. Using it enables you to manipulate the instance before it closes, e.g. activating `loading` for confirm button; you can invoke the `close` method registered on the instance to close the MessageBox instance.
 
 ```html
 <template>
@@ -210,7 +224,21 @@ Can be customized to show various content.
           message: 'This is a message',
           showCancelButton: true,
           confirmButtonText: 'OK',
-          cancelButtonText: 'Cancel'
+          cancelButtonText: 'Cancel',
+          beforeClose: (action, instance) => {
+            if (action === 'confirm') {
+              instance.confirmButtonLoading = true;
+              instance.confirmButtonText = 'Loading...';
+              setTimeout(() => {
+                instance.close();
+                setTimeout(() => {
+                  instance.confirmButtonLoading = false;
+                }, 300);
+              }, 3000);
+            } else {
+              instance.close();
+            }
+          }
         }).then(action => {
           this.$message({
             type: 'info',
@@ -247,6 +275,7 @@ The corresponding methods are: `MessageBox`, `MessageBox.alert`, `MessageBox.con
 | type | message type, used for icon display | string | success/info/warning/error | — |
 | customClass | custom class name for MessageBox | string | — | — |
 | callback | MessageBox closing callback if you don't prefer Promise | function(action), where action can be 'confirm' or 'cancel' | — | — |
+| beforeClose | callback before MessageBox closes, and it will prevent MessageBox from closing | function(action, instance), where `action` can be 'confirm' or 'cancel', and `instance` is the MessageBox instance. You can access to that instance's attributes and methods | — | — |
 | lockScroll | whether to lock body scroll when MessageBox prompts | boolean | — | true |
 | showCancelButton | whether to show a cancel button | boolean | — | false (true when called with confirm and prompt) |
 | showConfirmButton | whether to show a confirm button | boolean | — | true |

+ 32 - 3
examples/docs/zh-CN/message-box.md

@@ -65,7 +65,21 @@
           message: '这是一段内容, 这是一段内容, 这是一段内容, 这是一段内容, 这是一段内容, 这是一段内容, 这是一段内容',
           showCancelButton: true,
           confirmButtonText: '确定',
-          cancelButtonText: '取消'
+          cancelButtonText: '取消',
+          beforeClose: (action, instance) => {
+            if (action === 'confirm') {
+              instance.confirmButtonLoading = true;
+              instance.confirmButtonText = '执行中...';
+              setTimeout(() => {
+                instance.close();
+                setTimeout(() => {
+                  instance.confirmButtonLoading = false;
+                }, 300);
+              }, 3000);
+            } else {
+              instance.close();
+            }
+          }
         }).then(action => {
           setTimeout(() => {
             this.$message({
@@ -191,7 +205,7 @@
 
 可自定义配置不同内容。
 
-:::demo 以上三个方法都是对`$msgbox`方法的再包装。本例直接调用`$msgbox`方法,使用了`showCancelButton`字段,用于显示取消按钮。另外可使用`cancelButtonClass`为其添加自定义样式,使用`cancelButtonText`来自定义按钮文本Confirm 按钮也具有相同的字段,在文末的字段说明中有完整的字段列表。
+:::demo 以上三个方法都是对`$msgbox`方法的再包装。本例直接调用`$msgbox`方法,使用了`showCancelButton`字段,用于显示取消按钮。另外可使用`cancelButtonClass`为其添加自定义样式,使用`cancelButtonText`来自定义按钮文本Confirm 按钮也具有相同的字段,在文末的字段说明中有完整的字段列表)。此例还使用了`beforeClose`属性,它的值是一个方法,会在 MessageBox 的实例关闭前被调用,同时阻止实例的关闭。它有两个参数,分别为`action`和实例本身。使用它能够在关闭前对实例进行一些操作,比如为确定按钮添加`loading`状态等;此时若需要关闭实例,可以调用实例上的`close`方法
 
 ```html
 <template>
@@ -207,7 +221,21 @@
           message: '这是一段内容, 这是一段内容, 这是一段内容, 这是一段内容, 这是一段内容, 这是一段内容, 这是一段内容',
           showCancelButton: true,
           confirmButtonText: '确定',
-          cancelButtonText: '取消'
+          cancelButtonText: '取消',
+          beforeClose: (action, instance) => {
+            if (action === 'confirm') {
+              instance.confirmButtonLoading = true;
+              instance.confirmButtonText = '执行中...';
+              setTimeout(() => {
+                instance.close();
+                setTimeout(() => {
+                  instance.confirmButtonLoading = false;
+                }, 300);
+              }, 3000);
+            } else {
+              instance.close();
+            }
+          }
         }).then(action => {
           this.$message({
             type: 'info',
@@ -244,6 +272,7 @@ import { MessageBox } from 'element-ui';
 | type | 消息类型,用于显示图标 | string | success/info/warning/error | — |
 | customClass | MessageBox 的自定义类名 | string | — | — |
 | callback | 若不使用 Promise,可以使用此参数指定 MessageBox 关闭后的回调 | function(action),action 的值为'confirm'或'cancel' | — | — |
+| beforeClose | MessageBox 关闭前的回调,会阻止实例的关闭 | function(action, instance),action 的值为'confirm'或'cancel', instance 为 MessageBox 实例,可以通过它访问实例上的属性和方法 | — | — |
 | lockScroll | 是否在 MessageBox 出现时将 body 滚动锁定 | boolean | — | true |
 | showCancelButton | 是否显示取消按钮 | boolean | — | false(以 confirm 和 prompt 方式调用时为 true) |
 | showConfirmButton | 是否显示确定按钮 | boolean | — | true |

+ 27 - 5
packages/message-box/src/main.vue

@@ -15,8 +15,21 @@
           </div>
         </div>
         <div class="el-message-box__btns">
-          <el-button :class="[ cancelButtonClasses ]" v-show="showCancelButton" @click.native="handleAction('cancel')">{{ cancelButtonText || t('el.messagebox.cancel') }}</el-button>
-          <el-button ref="confirm" :class="[ confirmButtonClasses ]" v-show="showConfirmButton" @click.native="handleAction('confirm')">{{ confirmButtonText || t('el.messagebox.confirm') }}</el-button>
+          <el-button
+            :loading="cancelButtonLoading"
+            :class="[ cancelButtonClasses ]"
+            v-show="showCancelButton"
+            @click.native="handleAction('cancel')">
+            {{ cancelButtonText || t('el.messagebox.cancel') }}
+          </el-button>
+          <el-button
+            :loading="confirmButtonLoading"
+            ref="confirm"
+            :class="[ confirmButtonClasses ]"
+            v-show="showConfirmButton"
+            @click.native="handleAction('confirm')">
+            {{ confirmButtonText || t('el.messagebox.confirm') }}
+          </el-button>
         </div>
       </div>
     </div>
@@ -80,6 +93,7 @@
 
     methods: {
       doClose() {
+        if (!this.value) return;
         this.value = false;
         this._closing = true;
 
@@ -100,10 +114,12 @@
         if (!this.transition) {
           this.doAfterClose();
         }
+        if (this.action) this.callback(this.action, this);
       },
 
       handleWrapperClick() {
         if (this.closeOnClickModal) {
+          this.action = '';
           this.close();
         }
       },
@@ -112,9 +128,12 @@
         if (this.$type === 'prompt' && action === 'confirm' && !this.validate()) {
           return;
         }
-        var callback = this.callback;
-        this.value = false;
-        callback(action);
+        this.action = action;
+        if (typeof this.beforeClose === 'function') {
+          this.beforeClose(action, this);
+        } else {
+          this.close();
+        }
       },
 
       validate() {
@@ -186,8 +205,11 @@
         inputErrorMessage: '',
         showConfirmButton: true,
         showCancelButton: false,
+        action: '',
         confirmButtonText: '',
         cancelButtonText: '',
+        confirmButtonLoading: false,
+        cancelButtonLoading: false,
         confirmButtonClass: '',
         confirmButtonDisabled: false,
         cancelButtonClass: '',

+ 27 - 9
test/unit/specs/message-box.spec.js

@@ -142,16 +142,36 @@ describe('MessageBox', () => {
   });
 
   it('callback', done => {
+    let msgAction = '';
     MessageBox({
       title: '消息',
       message: '这是一段内容'
     }, action => {
-      expect(action).to.equal('cancel');
-      done();
+      msgAction = action;
     });
     setTimeout(() => {
       document.querySelector('.el-message-box__close').click();
-    }, 300);
+      expect(msgAction).to.equal('cancel');
+      done();
+    }, 50);
+  });
+
+  it('beforeClose', done => {
+    let msgAction = '';
+    MessageBox({
+      title: '消息',
+      message: '这是一段内容',
+      beforeClose: (action, instance) => {
+        instance.close();
+      }
+    }, action => {
+      msgAction = action;
+    });
+    setTimeout(() => {
+      document.querySelector('.el-message-box__wrapper .el-button--primary').click();
+      expect(msgAction).to.equal('confirm');
+      done();
+    }, 50);
   });
 
   describe('promise', () => {
@@ -162,9 +182,8 @@ describe('MessageBox', () => {
           done();
         });
       setTimeout(() => {
-        document.querySelector('.el-message-box__wrapper')
-          .querySelector('.el-button--primary').click();
-      }, 300);
+        document.querySelector('.el-message-box__wrapper .el-button--primary').click();
+      }, 50);
     });
 
     it('reject', done => {
@@ -174,9 +193,8 @@ describe('MessageBox', () => {
           done();
         });
       setTimeout(() => {
-        document.querySelector('.el-message-box__wrapper')
-          .querySelector('.el-button').click();
-      }, 300);
+        document.querySelector('.el-message-box__wrapper .el-button').click();
+      }, 50);
     });
   });
 });