使用element组定义v-loading
文件夹目录

src文件夹下面的directive.js
import vue from 'vue';
import loading from './loading.vue';
import { addclass, removeclass, getstyle } from 'element-ui/src/utils/dom';
import { popupmanager } from 'element-ui/src/utils/popup';
import afterleave from 'element-ui/src/utils/after-leave';
const mask = vue.extend(loading);
// mask 是一个虚拟dom
const loadingdirective = {};
loadingdirective.install = vue => {
if (vue.prototype.$isserver) return;
const toggleloading = (el, binding) => {
if (binding.value) {
vue.nexttick(() => {
if (binding.modifiers.fullscreen) {
el.originalposition = getstyle(document.body, 'position');
el.originaloverflow = getstyle(document.body, 'overflow');
el.maskstyle.zindex = popupmanager.nextzindex();
addclass(el.mask, 'is-fullscreen');
insertdom(document.body, el, binding);
} else {
removeclass(el.mask, 'is-fullscreen');
if (binding.modifiers.body) {
el.originalposition = getstyle(document.body, 'position');
['top', 'left'].foreach(property => {
const scroll = property === 'top' ? 'scrolltop' : 'scrollleft';
el.maskstyle[property] = el.getboundingclientrect()[property] +
document.body[scroll] +
document.documentelement[scroll] -
parseint(getstyle(document.body, `margin-${ property }`), 10) +
'px';
});
['height', 'width'].foreach(property => {
el.maskstyle[property] = el.getboundingclientrect()[property] + 'px';
});
insertdom(document.body, el, binding);
} else {
el.originalposition = getstyle(el, 'position');
insertdom(el, el, binding);
}
}
});
} else {
afterleave(el.instance, () => {
if (!el.instance.hiding) return;
el.domvisible = false;
const target = binding.modifiers.fullscreen || binding.modifiers.body
? document.body
: el;
removeclass(target, 'el-loading-parent--relative');
removeclass(target, 'el-loading-parent--hidden');
el.instance.hiding = false;
}, 300, true);
el.instance.visible = false;
el.instance.hiding = true;
}
};
const insertdom = (parent, el, binding) => {
if (!el.domvisible && getstyle(el, 'display') !== 'none' && getstyle(el, 'visibility') !== 'hidden') {
object.keys(el.maskstyle).foreach(property => {
el.mask.style[property] = el.maskstyle[property];
});
if (el.originalposition !== 'absolute' && el.originalposition !== 'fixed') {
addclass(parent, 'el-loading-parent--relative');
}
if (binding.modifiers.fullscreen && binding.modifiers.lock) {
addclass(parent, 'el-loading-parent--hidden');
}
el.domvisible = true;
parent.appendchild(el.mask);
vue.nexttick(() => {
if (el.instance.hiding) {
el.instance.$emit('after-leave');
} else {
el.instance.visible = true;
}
});
el.dominserted = true;
} else if (el.domvisible && el.instance.hiding === true) {
el.instance.visible = true;
el.instance.hiding = false;
}
};
vue.directive('loading', { // 自定义全局指令
bind: function(el, binding, vnode) {
const textexr = el.getattribute('element-loading-text');
const spinnerexr = el.getattribute('element-loading-spinner');
const backgroundexr = el.getattribute('element-loading-background');
const customclassexr = el.getattribute('element-loading-custom-class');
const vm = vnode.context;
const mask = new mask({
el: document.createelement('div'),
data: {
text: vm && vm[textexr] || textexr,
spinner: vm && vm[spinnerexr] || spinnerexr,
background: vm && vm[backgroundexr] || backgroundexr,
customclass: vm && vm[customclassexr] || customclassexr,
fullscreen: !!binding.modifiers.fullscreen
}
});
el.instance = mask;
el.mask = mask.$el;
el.maskstyle = {};
binding.value && toggleloading(el, binding);
},
update: function(el, binding) {
el.instance.settext(el.getattribute('element-loading-text'));
if (binding.oldvalue !== binding.value) {
toggleloading(el, binding);
}
},
unbind: function(el, binding) {
if (el.dominserted) {
el.mask &&
el.mask.parentnode &&
el.mask.parentnode.removechild(el.mask);
toggleloading(el, { value: false, modifiers: binding.modifiers });
}
el.instance && el.instance.$destroy();
}
});
};
export default loadingdirective;
index.js
import vue from 'vue';
import loadingvue from './loading.vue';
import { addclass, removeclass, getstyle } from 'element-ui/src/utils/dom';
import { popupmanager } from 'element-ui/src/utils/popup';
import afterleave from 'element-ui/src/utils/after-leave';
import merge from 'element-ui/src/utils/merge';
const loadingconstructor = vue.extend(loadingvue);
const defaults = {
text: null,
fullscreen: true,
body: false,
lock: false,
customclass: ''
};
let fullscreenloading;
loadingconstructor.prototype.originalposition = '';
loadingconstructor.prototype.originaloverflow = '';
loadingconstructor.prototype.close = function() {
if (this.fullscreen) {
fullscreenloading = undefined;
}
afterleave(this, () => {
const target = this.fullscreen || this.body
? document.body
: this.target;
removeclass(target, 'el-loading-parent--relative');
removeclass(target, 'el-loading-parent--hidden');
if (this.$el && this.$el.parentnode) {
this.$el.parentnode.removechild(this.$el);
}
this.$destroy();
}, 300);
this.visible = false;
};
const addstyle = (options, parent, instance) => {
let maskstyle = {};
if (options.fullscreen) {
instance.originalposition = getstyle(document.body, 'position');
instance.originaloverflow = getstyle(document.body, 'overflow');
maskstyle.zindex = popupmanager.nextzindex();
} else if (options.body) {
instance.originalposition = getstyle(document.body, 'position');
['top', 'left'].foreach(property => {
let scroll = property === 'top' ? 'scrolltop' : 'scrollleft';
maskstyle[property] = options.target.getboundingclientrect()[property] +
document.body[scroll] +
document.documentelement[scroll] +
'px';
});
['height', 'width'].foreach(property => {
maskstyle[property] = options.target.getboundingclientrect()[property] + 'px';
});
} else {
instance.originalposition = getstyle(parent, 'position');
}
object.keys(maskstyle).foreach(property => {
instance.$el.style[property] = maskstyle[property];
});
};
const loading = (options = {}) => {
if (vue.prototype.$isserver) return;
options = merge({}, defaults, options);
if (typeof options.target === 'string') {
options.target = document.queryselector(options.target);
}
options.target = options.target || document.body;
if (options.target !== document.body) {
options.fullscreen = false;
} else {
options.body = true;
}
if (options.fullscreen && fullscreenloading) {
return fullscreenloading;
}
let parent = options.body ? document.body : options.target;
let instance = new loadingconstructor({
el: document.createelement('div'),
data: options
});
addstyle(options, parent, instance);
if (instance.originalposition !== 'absolute' && instance.originalposition !== 'fixed') {
addclass(parent, 'el-loading-parent--relative');
}
if (options.fullscreen && options.lock) {
addclass(parent, 'el-loading-parent--hidden');
}
parent.appendchild(instance.$el);
vue.nexttick(() => {
instance.visible = true;
});
if (options.fullscreen) {
fullscreenloading = instance;
}
return instance;
};
export default loading;loading.vue (这是核心文件也就是在页面怎么展示效果的v-loading)
<template>
<div class="loading-index">
<transition name="el-loading-fade" @after-leave="handleafterleave">
<div
v-show="visible"
class="el-loading-mask"
:style="{ backgroundcolor: background || '' }"
:class="[customclass, { 'is-fullscreen': fullscreen }]"
>
<div class="el-loading-spinner">
<!-- <svg v-if="!spinner" class="circular" viewbox="25 25 50 50">
<circle class="path" cx="50" cy="50" r="20" fill="none"/>
</svg>
<i v-else :class="spinner"></i>
<p v-if="text" class="el-loading-text">{{ text }}</p> -->
<div class="number">
<span
v-for="(item, index) in 'loading...'"
:style="
'animation: totop 1.5s ' + 0.1 * index + 's infinite ease-out'
"
:key="index"
>
{{ item }}
</span>
</div>
</div>
</div>
</transition>
</div>
</template><script>
export default {
data() {
return {
text: null,
spinner: null,
background: null,
fullscreen: true,
visible: false,
customclass: "",
};
},
methods: {
handleafterleave() {
this.$emit("after-leave");
},
settext(text) {
this.text = text;
},
},
};
</script><style lang="less">
.loading-index {
.number {
line-height: 250px;
font-size: 24px;
color: #000;
text-align: center;
span {
position: relative;
margin-right: -6px;
}
}
@keyframes totop {
0% {
top: 0;
}
24% {
top: 0;
}
33% {
top: -7px;
}
39% {
top: -7px;
}
45% {
top: 0;
}
100% {
top: 0;
}
}
}
</style>在跟loading文件夹建立index.js(一定要跟src同级)
import directive from './src/directive';
import service from './src/index';
export default {
install(vue) {
vue.use(directive);
vue.prototype.$loading = service;
},
directive,
service
};在main.js中引入
注意:一定要注意先后顺序,否责无法实现

效果图片

总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论