ec2dc1d1 by 任超

feat:弹框

1 parent 9aa810bb
...@@ -21,4 +21,6 @@ yarn-error.log* ...@@ -21,4 +21,6 @@ yarn-error.log*
21 *.njsproj 21 *.njsproj
22 *.sln 22 *.sln
23 *.sw? 23 *.sw?
24 /api/config.js
25
24 package-lock.json 26 package-lock.json
......
...@@ -2,11 +2,13 @@ import dialogBox from '@/components/DialogBox/dialogBox.vue' ...@@ -2,11 +2,13 @@ import dialogBox from '@/components/DialogBox/dialogBox.vue'
2 import LbTable from '@/components/LbTable/lb-table.vue' 2 import LbTable from '@/components/LbTable/lb-table.vue'
3 import Theme from '@/components/Theme/theme.vue' 3 import Theme from '@/components/Theme/theme.vue'
4 import Popup from '@/components/Popup/index' 4 import Popup from '@/components/Popup/index'
5 import MessageBox from '@/components/MessageBox/index.js'
5 export default { 6 export default {
6 install: (Vue) => { 7 install: (Vue) => {
7 Vue.component('dialogBox', dialogBox); 8 Vue.component('dialogBox', dialogBox);
8 Vue.component('lbTable', LbTable); 9 Vue.component('lbTable', LbTable);
9 Vue.component('Theme', Theme); 10 Vue.component('Theme', Theme);
10 Vue.prototype.$popup = Popup.install 11 Vue.prototype.$popup = Popup.install;
12 Vue.prototype.$alertMes = MessageBox.alert;
11 } 13 }
12 } 14 }
...\ No newline at end of file ...\ No newline at end of file
......
1 import MessageBox from './src/main.js';
2 export default MessageBox;
1 const defaults = {
2 title: null,
3 message: '',
4 type: '',
5 iconClass: '',
6 showInput: false,
7 showClose: true,
8 modalFade: true,
9 lockScroll: true,
10 closeOnClickModal: true,
11 closeOnPressEscape: true,
12 closeOnHashChange: true,
13 inputValue: null,
14 inputPlaceholder: '',
15 inputType: 'text',
16 inputPattern: null,
17 inputValidator: null,
18 inputErrorMessage: '',
19 showConfirmButton: true,
20 showCancelButton: false,
21 confirmButtonPosition: 'right',
22 confirmButtonHighlight: false,
23 cancelButtonHighlight: false,
24 confirmButtonText: '',
25 cancelButtonText: '',
26 confirmButtonClass: '',
27 cancelButtonClass: '',
28 customClass: '',
29 beforeClose: null,
30 dangerouslyUseHTMLString: false,
31 center: false,
32 roundButton: false,
33 distinguishCancelAndClose: false
34 };
35
36 import Vue from 'vue';
37 import msgboxVue from './main.vue';
38 import merge from 'element-ui/src/utils/merge';
39 import { isVNode } from 'element-ui/src/utils/vdom';
40
41 const MessageBoxConstructor = Vue.extend(msgboxVue);
42
43 let currentMsg, instance;
44 let msgQueue = [];
45
46 const defaultCallback = action => {
47 if (currentMsg) {
48 let callback = currentMsg.callback;
49 if (typeof callback === 'function') {
50 if (instance.showInput) {
51 callback(instance.inputValue, action);
52 } else {
53 callback(action);
54 }
55 }
56 if (currentMsg.resolve) {
57 if (action === 'confirm') {
58 if (instance.showInput) {
59 currentMsg.resolve({ value: instance.inputValue, action });
60 } else {
61 currentMsg.resolve(action);
62 }
63 } else if (currentMsg.reject && (action === 'cancel' || action === 'close')) {
64 currentMsg.reject(action);
65 }
66 }
67 }
68 };
69
70 const initInstance = () => {
71 instance = new MessageBoxConstructor({
72 el: document.createElement('div')
73 });
74
75 instance.callback = defaultCallback;
76 };
77
78 const showNextMsg = () => {
79 if (!instance) {
80 initInstance();
81 }
82 instance.action = '';
83
84 if (!instance.visible || instance.closeTimer) {
85 if (msgQueue.length > 0) {
86 currentMsg = msgQueue.shift();
87
88 let options = currentMsg.options;
89 for (let prop in options) {
90 if (options.hasOwnProperty(prop)) {
91 instance[prop] = options[prop];
92 }
93 }
94 if (options.callback === undefined) {
95 instance.callback = defaultCallback;
96 }
97
98 let oldCb = instance.callback;
99 instance.callback = (action, instance) => {
100 oldCb(action, instance);
101 showNextMsg();
102 };
103 if (isVNode(instance.message)) {
104 instance.$slots.default = [instance.message];
105 instance.message = null;
106 } else {
107 delete instance.$slots.default;
108 }
109 ['modal', 'showClose', 'closeOnClickModal', 'closeOnPressEscape', 'closeOnHashChange'].forEach(prop => {
110 if (instance[prop] === undefined) {
111 instance[prop] = true;
112 }
113 });
114 document.body.appendChild(instance.$el);
115
116 Vue.nextTick(() => {
117 instance.visible = true;
118 });
119 }
120 }
121 };
122
123 const MessageBox = function(options, callback) {
124 if (Vue.prototype.$isServer) return;
125 if (typeof options === 'string' || isVNode(options)) {
126 options = {
127 message: options
128 };
129 if (typeof arguments[1] === 'string') {
130 options.title = arguments[1];
131 }
132 } else if (options.callback && !callback) {
133 callback = options.callback;
134 }
135
136 if (typeof Promise !== 'undefined') {
137 return new Promise((resolve, reject) => { // eslint-disable-line
138 msgQueue.push({
139 options: merge({}, defaults, MessageBox.defaults, options),
140 callback: callback,
141 resolve: resolve,
142 reject: reject
143 });
144
145 showNextMsg();
146 });
147 } else {
148 msgQueue.push({
149 options: merge({}, defaults, MessageBox.defaults, options),
150 callback: callback
151 });
152
153 showNextMsg();
154 }
155 };
156
157 MessageBox.setDefaults = defaults => {
158 MessageBox.defaults = defaults;
159 };
160
161 MessageBox.alert = (message, title, options) => {
162 if (typeof title === 'object') {
163 options = title;
164 title = '';
165 } else if (title === undefined) {
166 title = '';
167 }
168 return MessageBox(merge({
169 title: title,
170 message: message,
171 $type: 'alert',
172 closeOnPressEscape: false,
173 closeOnClickModal: false
174 }, options));
175 };
176
177 MessageBox.close = () => {
178 instance.doClose();
179 instance.visible = false;
180 msgQueue = [];
181 currentMsg = null;
182 };
183
184 export default MessageBox;
185 export { MessageBox };
1 <template>
2 <transition name="msgbox-fade">
3 <div class="el-message-box__wrapper" tabindex="-1" v-show="visible" @click.self="handleWrapperClick" role="dialog"
4 aria-modal="true" :aria-label="title || 'dialog'">
5 <div class="el-message-box" :class="[customClass, center && 'el-message-box--center']">
6 <div class="el-message-box__header" v-if="title !== null">
7 <div class="el-message-box__title">
8 <div :class="['el-message-box__status', icon]" v-if="icon && center">
9 </div>
10 <span>{{ title }}</span>
11 </div>
12 <button type="button" class="el-message-box__headerbtn" aria-label="Close" v-if="showClose"
13 @click="handleAction(distinguishCancelAndClose ? 'close' : 'cancel')"
14 @keydown.enter="handleAction(distinguishCancelAndClose ? 'close' : 'cancel')">
15 <i class="el-message-box__close el-icon-close"></i>
16 </button>
17 </div>
18 <div class="el-message-box__content">
19 <div class="el-message-box__message" v-if="message !== ''">
20 <slot>
21 <p>{{ message }}</p>
22 </slot>
23 </div>
24 </div>
25 </div>
26 </div>
27 </transition>
28 </template>
29
30 <script type="text/babel">
31 import Popup from 'element-ui/src/utils/popup';
32 import Locale from 'element-ui/src/mixins/locale';
33 import { addClass, removeClass } from 'element-ui/src/utils/dom';
34 import { t } from 'element-ui/src/locale';
35 import Dialog from 'element-ui/src/utils/aria-dialog';
36
37 let messageBox;
38 let typeMap = {
39 success: 'success',
40 info: 'info',
41 warning: 'warning',
42 error: 'error'
43 };
44
45 export default {
46 mixins: [Popup, Locale],
47
48 props: {
49 modal: {
50 default: true
51 },
52 lockScroll: {
53 default: true
54 },
55 showClose: {
56 type: Boolean,
57 default: true
58 },
59 closeOnClickModal: {
60 default: true
61 },
62 closeOnPressEscape: {
63 default: true
64 },
65 closeOnHashChange: {
66 default: true
67 },
68 center: {
69 default: false,
70 type: Boolean
71 },
72 roundButton: {
73 default: false,
74 type: Boolean
75 }
76 },
77
78 components: {
79 ElInput,
80 ElButton
81 },
82
83 computed: {
84 icon () {
85 const { type, iconClass } = this;
86 return iconClass || (type && typeMap[type] ? `el-icon-${typeMap[type]}` : '');
87 },
88
89 confirmButtonClasses () {
90 return `el-button--primary ${this.confirmButtonClass}`;
91 },
92 cancelButtonClasses () {
93 return `${this.cancelButtonClass}`;
94 }
95 },
96
97 methods: {
98 getSafeClose () {
99 const currentId = this.uid;
100 return () => {
101 this.$nextTick(() => {
102 if (currentId === this.uid) this.doClose();
103 });
104 };
105 },
106 doClose () {
107 if (!this.visible) return;
108 this.visible = false;
109 this._closing = true;
110
111 this.onClose && this.onClose();
112 messageBox.closeDialog(); // 解绑
113 if (this.lockScroll) {
114 setTimeout(this.restoreBodyStyle, 200);
115 }
116 this.opened = false;
117 this.doAfterClose();
118 setTimeout(() => {
119 if (this.action) this.callback(this.action, this);
120 });
121 },
122
123 handleWrapperClick () {
124 if (this.closeOnClickModal) {
125 this.handleAction(this.distinguishCancelAndClose ? 'close' : 'cancel');
126 }
127 },
128
129 handleInputEnter () {
130 if (this.inputType !== 'textarea') {
131 return this.handleAction('confirm');
132 }
133 },
134
135 handleAction (action) {
136 if (this.$type === 'prompt' && action === 'confirm' && !this.validate()) {
137 return;
138 }
139 this.action = action;
140 if (typeof this.beforeClose === 'function') {
141 this.close = this.getSafeClose();
142 this.beforeClose(action, this, this.close);
143 } else {
144 this.doClose();
145 }
146 },
147
148 validate () {
149 if (this.$type === 'prompt') {
150 const inputPattern = this.inputPattern;
151 if (inputPattern && !inputPattern.test(this.inputValue || '')) {
152 this.editorErrorMessage = this.inputErrorMessage || t('el.messagebox.error');
153 addClass(this.getInputElement(), 'invalid');
154 return false;
155 }
156 const inputValidator = this.inputValidator;
157 if (typeof inputValidator === 'function') {
158 const validateResult = inputValidator(this.inputValue);
159 if (validateResult === false) {
160 this.editorErrorMessage = this.inputErrorMessage || t('el.messagebox.error');
161 addClass(this.getInputElement(), 'invalid');
162 return false;
163 }
164 if (typeof validateResult === 'string') {
165 this.editorErrorMessage = validateResult;
166 addClass(this.getInputElement(), 'invalid');
167 return false;
168 }
169 }
170 }
171 this.editorErrorMessage = '';
172 removeClass(this.getInputElement(), 'invalid');
173 return true;
174 },
175 getFirstFocus () {
176 const btn = this.$el.querySelector('.el-message-box__btns .el-button');
177 const title = this.$el.querySelector('.el-message-box__btns .el-message-box__title');
178 return btn || title;
179 },
180 getInputElement () {
181 const inputRefs = this.$refs.input.$refs;
182 return inputRefs.input || inputRefs.textarea;
183 },
184 handleClose () {
185 this.handleAction('close');
186 }
187 },
188
189 watch: {
190 inputValue: {
191 immediate: true,
192 handler (val) {
193 this.$nextTick(_ => {
194 if (this.$type === 'prompt' && val !== null) {
195 this.validate();
196 }
197 });
198 }
199 },
200
201 visible (val) {
202 if (val) {
203 this.uid++;
204 if (this.$type === 'alert' || this.$type === 'confirm') {
205 this.$nextTick(() => {
206 this.$refs.confirm.$el.focus();
207 });
208 }
209 this.focusAfterClosed = document.activeElement;
210 messageBox = new Dialog(this.$el, this.focusAfterClosed, this.getFirstFocus());
211 }
212
213 // prompt
214 if (this.$type !== 'prompt') return;
215 if (val) {
216 setTimeout(() => {
217 if (this.$refs.input && this.$refs.input.$el) {
218 this.getInputElement().focus();
219 }
220 }, 500);
221 } else {
222 this.editorErrorMessage = '';
223 removeClass(this.getInputElement(), 'invalid');
224 }
225 }
226 },
227
228 mounted () {
229 this.$nextTick(() => {
230 if (this.closeOnHashChange) {
231 window.addEventListener('hashchange', this.close);
232 }
233 });
234 },
235
236 beforeDestroy () {
237 if (this.closeOnHashChange) {
238 window.removeEventListener('hashchange', this.close);
239 }
240 setTimeout(() => {
241 messageBox.closeDialog();
242 });
243 },
244
245 data () {
246 return {
247 uid: 1,
248 title: undefined,
249 message: '',
250 type: '',
251 iconClass: '',
252 customClass: '',
253 showInput: false,
254 inputValue: null,
255 inputPlaceholder: '',
256 inputType: 'text',
257 inputPattern: null,
258 inputValidator: null,
259 inputErrorMessage: '',
260 showConfirmButton: true,
261 showCancelButton: false,
262 action: '',
263 confirmButtonText: '',
264 cancelButtonText: '',
265 confirmButtonLoading: false,
266 cancelButtonLoading: false,
267 confirmButtonClass: '',
268 confirmButtonDisabled: false,
269 cancelButtonClass: '',
270 editorErrorMessage: null,
271 callback: null,
272 dangerouslyUseHTMLString: false,
273 focusAfterClosed: null,
274 isOnComposition: false,
275 distinguishCancelAndClose: false
276 };
277 }
278 };
279 </script>