设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间13 现在时间13 缓存数据 到现在一共是295天,有了人生中第一张迷你专辑,我期许自己这不会是句号,只会是个逗号,会一直一直一直突破的,直到我唱不动的那天。

到现在一共是295天,有了人生中第一张迷你专辑,我期许自己这不会是句号,只会是个逗号,会一直一直一直突破的,直到我唱不动的那天。 -- 一种原谅

查看: 1380|回复: 3

vue如何使用element组件自定义v-loading

[复制链接]

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
30
主题
28
精华
0
金钱
97
积分
60
注册时间
2023-9-30
最后登录
2025-5-31

发表于 2024-9-11 19:44:51 | 显示全部楼层 |阅读模式
目录


  • 使用element组定义v-loading

    • 文件夹目录
    • loading.vue (这是核心文件也就是在页面怎么展示效果的v-loading)
    • 效果图片

  • 总结

使用element组定义v-loading


文件夹目录

1.png

src文件夹下面的directive.js
  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. // Mask 是一个虚拟DOM
  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.           addClass(el.mask, 'is-fullscreen');
  19.           insertDom(document.body, el, binding);
  20.         } else {
  21.           removeClass(el.mask, 'is-fullscreen');

  22.           if (binding.modifiers.body) {
  23.             el.originalPosition = getStyle(document.body, 'position');

  24.             ['top', 'left'].forEach(property => {
  25.               const scroll = property === 'top' ? 'scrollTop' : 'scrollLeft';
  26.               el.maskStyle[property] = el.getBoundingClientRect()[property] +
  27.                 document.body[scroll] +
  28.                 document.documentElement[scroll] -
  29.                 parseInt(getStyle(document.body, `margin-${ property }`), 10) +
  30.                 'px';
  31.             });
  32.             ['height', 'width'].forEach(property => {
  33.               el.maskStyle[property] = el.getBoundingClientRect()[property] + 'px';
  34.             });

  35.             insertDom(document.body, el, binding);
  36.           } else {
  37.             el.originalPosition = getStyle(el, 'position');
  38.             insertDom(el, el, binding);
  39.           }
  40.         }
  41.       });
  42.     } else {
  43.       afterLeave(el.instance, () => {
  44.         if (!el.instance.hiding) return;
  45.         el.domVisible = false;
  46.         const target = binding.modifiers.fullscreen || binding.modifiers.body
  47.           ? document.body
  48.           : el;
  49.         removeClass(target, 'el-loading-parent--relative');
  50.         removeClass(target, 'el-loading-parent--hidden');
  51.         el.instance.hiding = false;
  52.       }, 300, true);
  53.       el.instance.visible = false;
  54.       el.instance.hiding = true;
  55.     }
  56.   };
  57.   const insertDom = (parent, el, binding) => {
  58.     if (!el.domVisible && getStyle(el, 'display') !== 'none' && getStyle(el, 'visibility') !== 'hidden') {
  59.       Object.keys(el.maskStyle).forEach(property => {
  60.         el.mask.style[property] = el.maskStyle[property];
  61.       });

  62.       if (el.originalPosition !== 'absolute' && el.originalPosition !== 'fixed') {
  63.         addClass(parent, 'el-loading-parent--relative');
  64.       }
  65.       if (binding.modifiers.fullscreen && binding.modifiers.lock) {
  66.         addClass(parent, 'el-loading-parent--hidden');
  67.       }
  68.       el.domVisible = true;

  69.       parent.appendChild(el.mask);
  70.       Vue.nextTick(() => {
  71.         if (el.instance.hiding) {
  72.           el.instance.$emit('after-leave');
  73.         } else {
  74.           el.instance.visible = true;
  75.         }
  76.       });
  77.       el.domInserted = true;
  78.     } else if (el.domVisible && el.instance.hiding === true) {
  79.       el.instance.visible = true;
  80.       el.instance.hiding = false;
  81.     }
  82.   };
  83.   Vue.directive('loading', { // 自定义全局指令
  84.     bind: function(el, binding, vnode) {
  85.       const textExr = el.getAttribute('element-loading-text');
  86.       const spinnerExr = el.getAttribute('element-loading-spinner');
  87.       const backgroundExr = el.getAttribute('element-loading-background');
  88.       const customClassExr = el.getAttribute('element-loading-custom-class');
  89.       const vm = vnode.context;
  90.       const mask = new Mask({
  91.         el: document.createElement('div'),
  92.         data: {
  93.           text: vm && vm[textExr] || textExr,
  94.           spinner: vm && vm[spinnerExr] || spinnerExr,
  95.           background: vm && vm[backgroundExr] || backgroundExr,
  96.           customClass: vm && vm[customClassExr] || customClassExr,
  97.           fullscreen: !!binding.modifiers.fullscreen
  98.         }
  99.       });
  100.       el.instance = mask;
  101.       el.mask = mask.$el;
  102.       el.maskStyle = {};

  103.       binding.value && toggleLoading(el, binding);
  104.     },
  105.     update: function(el, binding) {
  106.       el.instance.setText(el.getAttribute('element-loading-text'));
  107.       if (binding.oldValue !== binding.value) {
  108.         toggleLoading(el, binding);
  109.       }
  110.     },
  111.     unbind: function(el, binding) {
  112.       if (el.domInserted) {
  113.         el.mask &&
  114.         el.mask.parentNode &&
  115.         el.mask.parentNode.removeChild(el.mask);
  116.         toggleLoading(el, { value: false, modifiers: binding.modifiers });
  117.       }
  118.       el.instance && el.instance.$destroy();
  119.     }
  120.   });
  121. };

  122. export default loadingDirective;
复制代码
index.js
  1. import Vue from 'vue';
  2. import loadingVue 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. import merge from 'element-ui/src/utils/merge';

  7. const LoadingConstructor = Vue.extend(loadingVue);

  8. const defaults = {
  9.   text: null,
  10.   fullscreen: true,
  11.   body: false,
  12.   lock: false,
  13.   customClass: ''
  14. };

  15. let fullscreenLoading;

  16. LoadingConstructor.prototype.originalPosition = '';
  17. LoadingConstructor.prototype.originalOverflow = '';

  18. LoadingConstructor.prototype.close = function() {
  19.   if (this.fullscreen) {
  20.     fullscreenLoading = undefined;
  21.   }
  22.   afterLeave(this, () => {
  23.     const target = this.fullscreen || this.body
  24.       ? document.body
  25.       : this.target;
  26.     removeClass(target, 'el-loading-parent--relative');
  27.     removeClass(target, 'el-loading-parent--hidden');
  28.     if (this.$el && this.$el.parentNode) {
  29.       this.$el.parentNode.removeChild(this.$el);
  30.     }
  31.     this.$destroy();
  32.   }, 300);
  33.   this.visible = false;
  34. };

  35. const addStyle = (options, parent, instance) => {
  36.   let maskStyle = {};
  37.   if (options.fullscreen) {
  38.     instance.originalPosition = getStyle(document.body, 'position');
  39.     instance.originalOverflow = getStyle(document.body, 'overflow');
  40.     maskStyle.zIndex = PopupManager.nextZIndex();
  41.   } else if (options.body) {
  42.     instance.originalPosition = getStyle(document.body, 'position');
  43.     ['top', 'left'].forEach(property => {
  44.       let scroll = property === 'top' ? 'scrollTop' : 'scrollLeft';
  45.       maskStyle[property] = options.target.getBoundingClientRect()[property] +
  46.         document.body[scroll] +
  47.         document.documentElement[scroll] +
  48.         'px';
  49.     });
  50.     ['height', 'width'].forEach(property => {
  51.       maskStyle[property] = options.target.getBoundingClientRect()[property] + 'px';
  52.     });
  53.   } else {
  54.     instance.originalPosition = getStyle(parent, 'position');
  55.   }
  56.   Object.keys(maskStyle).forEach(property => {
  57.     instance.$el.style[property] = maskStyle[property];
  58.   });
  59. };
  60. const Loading = (options = {}) => {
  61.   if (Vue.prototype.$isServer) return;
  62.   options = merge({}, defaults, options);
  63.   if (typeof options.target === 'string') {
  64.     options.target = document.querySelector(options.target);
  65.   }
  66.   options.target = options.target || document.body;
  67.   if (options.target !== document.body) {
  68.     options.fullscreen = false;
  69.   } else {
  70.     options.body = true;
  71.   }
  72.   if (options.fullscreen && fullscreenLoading) {
  73.     return fullscreenLoading;
  74.   }

  75.   let parent = options.body ? document.body : options.target;
  76.   let instance = new LoadingConstructor({
  77.     el: document.createElement('div'),
  78.     data: options
  79.   });
  80.   addStyle(options, parent, instance);
  81.   if (instance.originalPosition !== 'absolute' && instance.originalPosition !== 'fixed') {
  82.     addClass(parent, 'el-loading-parent--relative');
  83.   }
  84.   if (options.fullscreen && options.lock) {
  85.     addClass(parent, 'el-loading-parent--hidden');
  86.   }
  87.   parent.appendChild(instance.$el);
  88.   Vue.nextTick(() => {
  89.     instance.visible = true;
  90.   });
  91.   if (options.fullscreen) {
  92.     fullscreenLoading = instance;
  93.   }
  94.   return instance;
  95. };
  96. export default Loading;
复制代码
loading.vue (这是核心文件也就是在页面怎么展示效果的v-loading)
  1. <template>
  2.   <div class="loading-index">
  3.     <transition name="el-loading-fade" @after-leave="handleAfterLeave">
  4.       <div
  5.         v-show="visible"
  6.         class="el-loading-mask"
  7.         :style="{ backgroundColor: background || '' }"
  8.         :class="[customClass, { 'is-fullscreen': fullscreen }]"
  9.       >
  10.         <div class="el-loading-spinner">
  11.           <!-- <svg v-if="!spinner" class="circular" viewBox="25 25 50 50">
  12.           <circle class="path" cx="50" cy="50" r="20" fill="none"/>
  13.         </svg>
  14.         <i v-else :class="spinner"></i>
  15.         <p v-if="text" class="el-loading-text">{{ text }}</p> -->
  16.           <div class="number">
  17.             <span
  18.               v-for="(item, index) in 'loading...'"
  19.               :style="
  20.                 'animation: totop 1.5s ' + 0.1 * index + 's infinite ease-out'
  21.               "
  22.               :key="index"
  23.             >
  24.               {{ item }}
  25.             </span>
  26.           </div>
  27.         </div>
  28.       </div>
  29.     </transition>
  30.   </div>
  31. </template>
复制代码
  1. <script>
  2. export default {
  3.   data() {
  4.     return {
  5.       text: null,
  6.       spinner: null,
  7.       background: null,
  8.       fullscreen: true,
  9.       visible: false,
  10.       customClass: "",
  11.     };
  12.   },

  13.   methods: {
  14.     handleAfterLeave() {
  15.       this.$emit("after-leave");
  16.     },
  17.     setText(text) {
  18.       this.text = text;
  19.     },
  20.   },
  21. };
  22. </script>
复制代码
  1. <style lang="less">
  2. .loading-index {
  3.   .number {
  4.     line-height: 250px;
  5.     font-size: 24px;
  6.     color: #000;
  7.     text-align: center;
  8.     span {
  9.       position: relative;
  10.       margin-right: -6px;
  11.     }
  12.   }
  13.   @keyframes totop {
  14.     0% {
  15.       top: 0;
  16.     }
  17.     24% {
  18.       top: 0;
  19.     }
  20.     33% {
  21.       top: -7px;
  22.     }
  23.     39% {
  24.       top: -7px;
  25.     }
  26.     45% {
  27.       top: 0;
  28.     }
  29.     100% {
  30.       top: 0;
  31.     }
  32.   }
  33. }
  34. </style>
复制代码
在跟loading文件夹建立index.js(一定要跟src同级)
  1. import directive from './src/directive';
  2. import service from './src/index';
  3. export default {
  4.   install(Vue) {
  5.     Vue.use(directive);
  6.     Vue.prototype.$loading = service;
  7.   },
  8.   directive,
  9.   service
  10. };
复制代码
在main.js中引入
注意:一定要注意先后顺序,否责无法实现
2.png


效果图片

3.png


总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持晓枫资讯。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
12
积分
4
注册时间
2023-7-8
最后登录
2023-7-8

发表于 2024-10-29 07:32:31 | 显示全部楼层
顶顶更健康!!!
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

  • 打卡等级:无名新人
  • 打卡总天数:1
  • 打卡月天数:0
  • 打卡总奖励:18
  • 最近打卡:2024-12-04 16:13:35
等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
31
积分
6
注册时间
2023-6-23
最后登录
2024-12-4

发表于 2025-2-23 03:08:46 | 显示全部楼层
感谢楼主,顶。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
12
积分
4
注册时间
2023-8-19
最后登录
2023-8-19

发表于 昨天 08:57 | 显示全部楼层
感谢楼主分享。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼
4楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表