使用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中引入
注意:一定要注意先后顺序,否责无法实现
效果图片
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论