1 | import Vue from 'vue';
|
2 | import Loading from './loading.vue';
|
3 | import { addClass, removeClass, getStyle } from 'element-ui/src/utils/dom';
|
4 | import { PopupManager } from 'element-ui/src/utils/popup';
|
5 | import afterLeave from 'element-ui/src/utils/after-leave';
|
6 | const Mask = Vue.extend(Loading);
|
7 |
|
8 | const loadingDirective = {};
|
9 | loadingDirective.install = Vue => {
|
10 | if (Vue.prototype.$isServer) return;
|
11 | const toggleLoading = (el, binding) => {
|
12 | if (binding.value) {
|
13 | Vue.nextTick(() => {
|
14 | if (binding.modifiers.fullscreen) {
|
15 | el.originalPosition = getStyle(document.body, 'position');
|
16 | el.originalOverflow = getStyle(document.body, 'overflow');
|
17 | el.maskStyle.zIndex = PopupManager.nextZIndex();
|
18 |
|
19 | addClass(el.mask, 'is-fullscreen');
|
20 | insertDom(document.body, el, binding);
|
21 | } else {
|
22 | removeClass(el.mask, 'is-fullscreen');
|
23 |
|
24 | if (binding.modifiers.body) {
|
25 | el.originalPosition = getStyle(document.body, 'position');
|
26 |
|
27 | ['top', 'left'].forEach(property => {
|
28 | const scroll = property === 'top' ? 'scrollTop' : 'scrollLeft';
|
29 | el.maskStyle[property] = el.getBoundingClientRect()[property] +
|
30 | document.body[scroll] +
|
31 | document.documentElement[scroll] -
|
32 | parseInt(getStyle(document.body, `margin-${ property }`), 10) +
|
33 | 'px';
|
34 | });
|
35 | ['height', 'width'].forEach(property => {
|
36 | el.maskStyle[property] = el.getBoundingClientRect()[property] + 'px';
|
37 | });
|
38 |
|
39 | insertDom(document.body, el, binding);
|
40 | } else {
|
41 | el.originalPosition = getStyle(el, 'position');
|
42 | insertDom(el, el, binding);
|
43 | }
|
44 | }
|
45 | });
|
46 | } else {
|
47 | afterLeave(el.instance, _ => {
|
48 | el.domVisible = false;
|
49 | const target = binding.modifiers.fullscreen || binding.modifiers.body
|
50 | ? document.body
|
51 | : el;
|
52 | removeClass(target, 'el-loading-parent--relative');
|
53 | removeClass(target, 'el-loading-parent--hidden');
|
54 | el.instance.hiding = false;
|
55 | }, 300, true);
|
56 | el.instance.visible = false;
|
57 | el.instance.hiding = true;
|
58 | }
|
59 | };
|
60 | const insertDom = (parent, el, binding) => {
|
61 | if (!el.domVisible && getStyle(el, 'display') !== 'none' && getStyle(el, 'visibility') !== 'hidden') {
|
62 | Object.keys(el.maskStyle).forEach(property => {
|
63 | el.mask.style[property] = el.maskStyle[property];
|
64 | });
|
65 |
|
66 | if (el.originalPosition !== 'absolute' && el.originalPosition !== 'fixed') {
|
67 | addClass(parent, 'el-loading-parent--relative');
|
68 | }
|
69 | if (binding.modifiers.fullscreen && binding.modifiers.lock) {
|
70 | addClass(parent, 'el-loading-parent--hidden');
|
71 | }
|
72 | el.domVisible = true;
|
73 |
|
74 | parent.appendChild(el.mask);
|
75 | Vue.nextTick(() => {
|
76 | if (el.instance.hiding) {
|
77 | el.instance.$emit('after-leave');
|
78 | } else {
|
79 | el.instance.visible = true;
|
80 | }
|
81 | });
|
82 | el.domInserted = true;
|
83 | }
|
84 | };
|
85 |
|
86 | Vue.directive('loading', {
|
87 | bind: function(el, binding, vnode) {
|
88 | const textExr = el.getAttribute('element-loading-text');
|
89 | const spinnerExr = el.getAttribute('element-loading-spinner');
|
90 | const backgroundExr = el.getAttribute('element-loading-background');
|
91 | const customClassExr = el.getAttribute('element-loading-custom-class');
|
92 | const vm = vnode.context;
|
93 | const mask = new Mask({
|
94 | el: document.createElement('div'),
|
95 | data: {
|
96 | text: vm && vm[textExr] || textExr,
|
97 | spinner: vm && vm[spinnerExr] || spinnerExr,
|
98 | background: vm && vm[backgroundExr] || backgroundExr,
|
99 | customClass: vm && vm[customClassExr] || customClassExr,
|
100 | fullscreen: !!binding.modifiers.fullscreen
|
101 | }
|
102 | });
|
103 | el.instance = mask;
|
104 | el.mask = mask.$el;
|
105 | el.maskStyle = {};
|
106 |
|
107 | binding.value && toggleLoading(el, binding);
|
108 | },
|
109 |
|
110 | update: function(el, binding) {
|
111 | el.instance.setText(el.getAttribute('element-loading-text'));
|
112 | if (binding.oldValue !== binding.value) {
|
113 | toggleLoading(el, binding);
|
114 | }
|
115 | },
|
116 |
|
117 | unbind: function(el, binding) {
|
118 | if (el.domInserted) {
|
119 | el.mask &&
|
120 | el.mask.parentNode &&
|
121 | el.mask.parentNode.removeChild(el.mask);
|
122 | toggleLoading(el, { value: false, modifiers: binding.modifiers });
|
123 | }
|
124 | }
|
125 | });
|
126 | };
|
127 |
|
128 | export default loadingDirective;
|