<template> <transition name="msgbox-fade"> <div class="el-message-box__wrapper md-message-box__wrapper" tabindex="-1" v-show="visible" @click.self="handleWrapperClick" role="dialog" aria-modal="true" :aria-label="title || 'dialog'" > <div class="el-message-box" :class="[customClass, center && 'el-message-box--center']" > <div class="el-message-box__header"> <div class="el-message-box__title-icon"> <img v-if="iconType && iconType == 'success'" src="@/assets/images/dialog/success_icon.png" /> <img v-else src="@/assets/images/dialog/info_icon.png" /> </div> </div> <div class="el-message-box__content"> <div class="el-message-box__message" v-if="message !== ''" > <slot> <p v-if="!dangerouslyUseHTMLString">{{ message }}</p> <p v-else v-html="message" ></p> </slot> </div> <div class="el-message-box__input" v-show="showInput" > <el-input v-model="inputValue" :type="inputType" @keydown.enter.native="handleInputEnter" :placeholder="inputPlaceholder" ref="input" ></el-input> <div class="el-message-box__errormsg" :style="{ visibility: !!editorErrorMessage ? 'visible' : 'hidden' }" >{{ editorErrorMessage }}</div> </div> </div> <div class="el-message-box__btns"> <el-button :loading="cancelButtonLoading" :class="[ cancelButtonClasses ]" v-if="showCancelButton" :round="roundButton" size="small" @click.native="handleAction('cancel')" @keydown.enter="handleAction('cancel')" > {{ cancelButtonText }} </el-button> <el-button :loading="confirmButtonLoading" ref="confirm" :class="[ confirmButtonClasses ]" v-show="showConfirmButton" :round="roundButton" size="small" @click.native="handleAction('confirm')" @keydown.enter="handleAction('confirm')" > {{ confirmButtonText }} </el-button> </div> </div> </div> </transition> </template> <script> import Dialog from 'element-ui/src/utils/aria-dialog'; import Popup from '../Popup/index.js'; import { addClass, removeClass } from 'element-ui/src/utils/dom'; let messageBox; let typeMap = { success: 'success', info: 'info', warning: 'warning', error: 'error', }; export default { mixins: [Popup], props: { modal: { default: true, }, lockScroll: { default: true, }, showClose: { type: Boolean, default: true, }, closeOnClickModal: { default: true, }, closeOnPressEscape: { default: true, }, closeOnHashChange: { default: true, }, center: { default: false, type: Boolean, }, roundButton: { default: false, type: Boolean, }, }, data() { return { uid: 1, title: undefined, message: '', type: '', iconClass: '', customClass: '', showInput: false, inputValue: null, inputPlaceholder: '', inputType: 'text', inputPattern: null, inputValidator: null, inputErrorMessage: '', showConfirmButton: true, showCancelButton: false, action: '', confirmButtonText: '', cancelButtonText: '', confirmButtonLoading: false, cancelButtonLoading: false, confirmButtonClass: '', confirmButtonDisabled: false, cancelButtonClass: '', editorErrorMessage: null, callback: null, dangerouslyUseHTMLString: false, focusAfterClosed: null, isOnComposition: false, distinguishCancelAndClose: false, iconType: '', }; }, computed: { icon() { const { type, iconClass } = this; return ( iconClass || (type && typeMap[type] ? `el-icon-${typeMap[type]}` : '') ); }, confirmButtonClasses() { return `el-button--primary ${this.confirmButtonClass}`; }, cancelButtonClasses() { return `${this.cancelButtonClass}`; }, }, watch: { inputValue: { immediate: true, handler(val) { this.$nextTick(_ => { if (this.$type === 'prompt' && val !== null) { this.validate(); } }); }, }, visible(val) { if (val) { this.uid++; if ( this.$type === 'alert' || this.$type === 'confirm' || this.$type === 'success' || this.$type === 'info' ) { this.$nextTick(() => { this.$refs.confirm.$el.focus(); }); } this.focusAfterClosed = document.activeElement; messageBox = new Dialog( this.$el, this.focusAfterClosed, this.getFirstFocus() ); } // prompt if (this.$type !== 'prompt') return; if (val) { setTimeout(() => { if (this.$refs.input && this.$refs.input.$el) { this.getInputElement().focus(); } }, 500); } else { this.editorErrorMessage = ''; removeClass(this.getInputElement(), 'invalid'); } }, }, mounted() { this.$nextTick(() => { if (this.closeOnHashChange) { window.addEventListener('hashchange', this.close); } }); }, beforeDestroy() { if (this.closeOnHashChange) { window.removeEventListener('hashchange', this.close); } setTimeout(() => { messageBox.closeDialog(); }); }, methods: { getSafeClose() { const currentId = this.uid; return () => { this.$nextTick(() => { if (currentId === this.uid) this.doClose(); }); }; }, doClose() { if (!this.visible) return; this.visible = false; this._closing = true; this.onClose && this.onClose(); messageBox.closeDialog(); // 解绑 if (this.lockScroll) { setTimeout(this.restoreBodyStyle, 200); } this.opened = false; this.doAfterClose(); setTimeout(() => { if (this.action) this.callback(this.action, this); }); }, handleWrapperClick() { if (this.closeOnClickModal) { this.handleAction(this.distinguishCancelAndClose ? 'close' : 'cancel'); } }, handleInputEnter() { if (this.inputType !== 'textarea') { return this.handleAction('confirm'); } }, handleAction(action) { if (this.$type === 'prompt' && action === 'confirm' && !this.validate()) { return; } this.action = action; if (typeof this.beforeClose === 'function') { this.close = this.getSafeClose(); this.beforeClose(action, this, this.close); } else { this.doClose(); } }, validate() { if (this.$type === 'prompt') { const inputPattern = this.inputPattern; if (inputPattern && !inputPattern.test(this.inputValue || '')) { this.editorErrorMessage = this.inputErrorMessage; addClass(this.getInputElement(), 'invalid'); return false; } const inputValidator = this.inputValidator; if (typeof inputValidator === 'function') { const validateResult = inputValidator(this.inputValue); if (validateResult === false) { this.editorErrorMessage = this.inputErrorMessage; addClass(this.getInputElement(), 'invalid'); return false; } if (typeof validateResult === 'string') { this.editorErrorMessage = validateResult; addClass(this.getInputElement(), 'invalid'); return false; } } } this.editorErrorMessage = ''; removeClass(this.getInputElement(), 'invalid'); return true; }, getFirstFocus() { const btn = this.$el.querySelector('.el-message-box__btns .el-button'); const title = this.$el.querySelector( '.el-message-box__btns .el-message-box__title' ); return btn || title; }, getInputElement() { const inputRefs = this.$refs.input.$refs; return inputRefs.input || inputRefs.textarea; }, }, }; </script> <style lang="scss"> .el-message-box__wrapper.md-message-box__wrapper { .el-message-box { border: none; border-radius: 8px; box-shadow: 2px 2px 10px #666; padding-bottom: 30px; } .el-message-box__header { position: relative; height: 110px; background-color: #4e82fb; .el-message-box__title-icon { position: absolute; width: 110px; height: 110px; top: 50px; left: 50%; transform: translate(-50%, 0); } } .el-message-box__content { box-sizing: content-box; padding: 50px 20px 0; height: 130px; text-align: center; font-size: 24px; display: flex; align-items: center; justify-content: center; } .el-message-box__btns { text-align: center; padding: 0; button { height: 40px; line-height: 40px; font-size: 18px; padding: 0 18px; } } } </style>