UNPKG

9.64 kBPlain TextView Raw
1<template>
2 <transition name="msgbox-fade">
3 <div
4 class="el-message-box__wrapper"
5 tabindex="-1"
6 v-show="visible"
7 @click.self="handleWrapperClick"
8 role="dialog"
9 aria-modal="true"
10 :aria-label="title || 'dialog'">
11 <div class="el-message-box" :class="[customClass, center && 'el-message-box--center']">
12 <div class="el-message-box__header" v-if="title !== null">
13 <div class="el-message-box__title">
14 <div
15 :class="['el-message-box__status', icon]"
16 v-if="icon && center">
17 </div>
18 <span>{{ title }}</span>
19 </div>
20 <button
21 type="button"
22 class="el-message-box__headerbtn"
23 aria-label="Close"
24 v-if="showClose"
25 @click="handleAction(distinguishCancelAndClose ? 'close' : 'cancel')"
26 @keydown.enter="handleAction(distinguishCancelAndClose ? 'close' : 'cancel')">
27 <i class="el-message-box__close el-icon-close"></i>
28 </button>
29 </div>
30 <div class="el-message-box__content">
31 <div
32 :class="['el-message-box__status', icon]"
33 v-if="icon && !center && message !== ''">
34 </div>
35 <div class="el-message-box__message" v-if="message !== ''">
36 <slot>
37 <p v-if="!dangerouslyUseHTMLString">{{ message }}</p>
38 <p v-else v-html="message"></p>
39 </slot>
40 </div>
41 <div class="el-message-box__input" v-show="showInput">
42 <el-input
43 v-model="inputValue"
44 :type="inputType"
45 @keydown.enter.native="handleInputEnter"
46 :placeholder="inputPlaceholder"
47 ref="input"></el-input>
48 <div class="el-message-box__errormsg" :style="{ visibility: !!editorErrorMessage ? 'visible' : 'hidden' }">{{ editorErrorMessage }}</div>
49 </div>
50 </div>
51 <div class="el-message-box__btns">
52 <el-button
53 :loading="cancelButtonLoading"
54 :class="[ cancelButtonClasses ]"
55 v-if="showCancelButton"
56 :round="roundButton"
57 size="small"
58 @click.native="handleAction('cancel')"
59 @keydown.enter="handleAction('cancel')">
60 {{ cancelButtonText || t('el.messagebox.cancel') }}
61 </el-button>
62 <el-button
63 :loading="confirmButtonLoading"
64 ref="confirm"
65 :class="[ confirmButtonClasses ]"
66 v-show="showConfirmButton"
67 :round="roundButton"
68 size="small"
69 @click.native="handleAction('confirm')"
70 @keydown.enter="handleAction('confirm')">
71 {{ confirmButtonText || t('el.messagebox.confirm') }}
72 </el-button>
73 </div>
74 </div>
75 </div>
76 </transition>
77</template>
78
79<script type="text/babel">
80 import Popup from 'element-ui/src/utils/popup';
81 import Locale from 'element-ui/src/mixins/locale';
82 import ElInput from 'element-ui/packages/input';
83 import ElButton from 'element-ui/packages/button';
84 import { addClass, removeClass } from 'element-ui/src/utils/dom';
85 import { t } from 'element-ui/src/locale';
86 import Dialog from 'element-ui/src/utils/aria-dialog';
87
88 let messageBox;
89 let typeMap = {
90 success: 'success',
91 info: 'info',
92 warning: 'warning',
93 error: 'error'
94 };
95
96 export default {
97 mixins: [Popup, Locale],
98
99 props: {
100 modal: {
101 default: true
102 },
103 lockScroll: {
104 default: true
105 },
106 showClose: {
107 type: Boolean,
108 default: true
109 },
110 closeOnClickModal: {
111 default: true
112 },
113 closeOnPressEscape: {
114 default: true
115 },
116 closeOnHashChange: {
117 default: true
118 },
119 center: {
120 default: false,
121 type: Boolean
122 },
123 roundButton: {
124 default: false,
125 type: Boolean
126 }
127 },
128
129 components: {
130 ElInput,
131 ElButton
132 },
133
134 computed: {
135 icon() {
136 const { type, iconClass } = this;
137 return iconClass || (type && typeMap[type] ? `el-icon-${ typeMap[type] }` : '');
138 },
139
140 confirmButtonClasses() {
141 return `el-button--primary ${ this.confirmButtonClass }`;
142 },
143 cancelButtonClasses() {
144 return `${ this.cancelButtonClass }`;
145 }
146 },
147
148 methods: {
149 getSafeClose() {
150 const currentId = this.uid;
151 return () => {
152 this.$nextTick(() => {
153 if (currentId === this.uid) this.doClose();
154 });
155 };
156 },
157 doClose() {
158 if (!this.visible) return;
159 this.visible = false;
160 this._closing = true;
161
162 this.onClose && this.onClose();
163 messageBox.closeDialog(); // 解绑
164 if (this.lockScroll) {
165 setTimeout(this.restoreBodyStyle, 200);
166 }
167 this.opened = false;
168 this.doAfterClose();
169 setTimeout(() => {
170 if (this.action) this.callback(this.action, this);
171 });
172 },
173
174 handleWrapperClick() {
175 if (this.closeOnClickModal) {
176 this.handleAction(this.distinguishCancelAndClose ? 'close' : 'cancel');
177 }
178 },
179
180 handleInputEnter() {
181 if (this.inputType !== 'textarea') {
182 return this.handleAction('confirm');
183 }
184 },
185
186 handleAction(action) {
187 if (this.$type === 'prompt' && action === 'confirm' && !this.validate()) {
188 return;
189 }
190 this.action = action;
191 if (typeof this.beforeClose === 'function') {
192 this.close = this.getSafeClose();
193 this.beforeClose(action, this, this.close);
194 } else {
195 this.doClose();
196 }
197 },
198
199 validate() {
200 if (this.$type === 'prompt') {
201 const inputPattern = this.inputPattern;
202 if (inputPattern && !inputPattern.test(this.inputValue || '')) {
203 this.editorErrorMessage = this.inputErrorMessage || t('el.messagebox.error');
204 addClass(this.getInputElement(), 'invalid');
205 return false;
206 }
207 const inputValidator = this.inputValidator;
208 if (typeof inputValidator === 'function') {
209 const validateResult = inputValidator(this.inputValue);
210 if (validateResult === false) {
211 this.editorErrorMessage = this.inputErrorMessage || t('el.messagebox.error');
212 addClass(this.getInputElement(), 'invalid');
213 return false;
214 }
215 if (typeof validateResult === 'string') {
216 this.editorErrorMessage = validateResult;
217 addClass(this.getInputElement(), 'invalid');
218 return false;
219 }
220 }
221 }
222 this.editorErrorMessage = '';
223 removeClass(this.getInputElement(), 'invalid');
224 return true;
225 },
226 getFirstFocus() {
227 const btn = this.$el.querySelector('.el-message-box__btns .el-button');
228 const title = this.$el.querySelector('.el-message-box__btns .el-message-box__title');
229 return btn || title;
230 },
231 getInputElement() {
232 const inputRefs = this.$refs.input.$refs;
233 return inputRefs.input || inputRefs.textarea;
234 }
235 },
236
237 watch: {
238 inputValue: {
239 immediate: true,
240 handler(val) {
241 this.$nextTick(_ => {
242 if (this.$type === 'prompt' && val !== null) {
243 this.validate();
244 }
245 });
246 }
247 },
248
249 visible(val) {
250 if (val) {
251 this.uid++;
252 if (this.$type === 'alert' || this.$type === 'confirm') {
253 this.$nextTick(() => {
254 this.$refs.confirm.$el.focus();
255 });
256 }
257 this.focusAfterClosed = document.activeElement;
258 messageBox = new Dialog(this.$el, this.focusAfterClosed, this.getFirstFocus());
259 }
260
261 // prompt
262 if (this.$type !== 'prompt') return;
263 if (val) {
264 setTimeout(() => {
265 if (this.$refs.input && this.$refs.input.$el) {
266 this.getInputElement().focus();
267 }
268 }, 500);
269 } else {
270 this.editorErrorMessage = '';
271 removeClass(this.getInputElement(), 'invalid');
272 }
273 }
274 },
275
276 mounted() {
277 this.$nextTick(() => {
278 if (this.closeOnHashChange) {
279 window.addEventListener('hashchange', this.close);
280 }
281 });
282 },
283
284 beforeDestroy() {
285 if (this.closeOnHashChange) {
286 window.removeEventListener('hashchange', this.close);
287 }
288 setTimeout(() => {
289 messageBox.closeDialog();
290 });
291 },
292
293 data() {
294 return {
295 uid: 1,
296 title: undefined,
297 message: '',
298 type: '',
299 iconClass: '',
300 customClass: '',
301 showInput: false,
302 inputValue: null,
303 inputPlaceholder: '',
304 inputType: 'text',
305 inputPattern: null,
306 inputValidator: null,
307 inputErrorMessage: '',
308 showConfirmButton: true,
309 showCancelButton: false,
310 action: '',
311 confirmButtonText: '',
312 cancelButtonText: '',
313 confirmButtonLoading: false,
314 cancelButtonLoading: false,
315 confirmButtonClass: '',
316 confirmButtonDisabled: false,
317 cancelButtonClass: '',
318 editorErrorMessage: null,
319 callback: null,
320 dangerouslyUseHTMLString: false,
321 focusAfterClosed: null,
322 isOnComposition: false,
323 distinguishCancelAndClose: false
324 };
325 }
326 };
327</script>