网站成果演示:http://ashuai.work:8888/#/myLoad
GitHub仓库地址代码:https://github.com/shuirongsh...
加载中思路剖析
实现加载中成果,个别有两种形式:
- 第一种是:搞一个
load组件
,而后应用Vue.extend()办法
去继承一个加载组件去应用,比方笔者的这篇文章:https://segmentfault.com/a/11... - 第二种是:间接应用指令去在须要加载的
dom
下来创立一个加载中的dom
元素,并指定相应的款式即可。本篇文章说的是第二种。
咱们先看一下效果图
v-load效果图
实现步骤一:加上自定义指令
假如我有一个dom元素,我给其加上一个自定义的指令v-load="loading"
,绑定一个具体的布尔值loading
,用于管制开启加载中和敞开加载中
<div class="box" v-load="loading">111</div>loading: true.box { width: 160px; height: 80px; border: 2px solid #666;}
接下来,我就要在自定义指令的相干钩子函数中去操作这个dom
元素。
对于自定义指令的入门基础知识能够看官网文档,或者参见笔者之前的对于自定义指令的文章:https://segmentfault.com/a/11...
实现步骤二:给指标元素创立一个子元素dom用于加载
在自定义指令的初始化bind钩子
函数中,咱们能够拿到这个dom
元素,首先给这个指标元素开始绝对定位,让用于加载中的子元素dom
去相对定位,以这个绝对定位的父元素进行参考
bind(el, binding) { const target = el; // 父元素绝对定位 target.style.position = "relative"; // 子元素遮罩层局部 let loadChild = document.createElement("div"); loadChild.className = "loadClass";}
上述代码中给加载中的子元素loadChild
指定一个款式类名loadClass
在这里小伙伴可能有疑难了,这个自定义指令的款式怎么写呢?自定义指令中也没有style
标签啊?
是的,自定义指令中不能间接写款式,不过没关系,咱们能够先写好一个css
款式,而后引入过去应用啊,如下:
// 引入拆分的款式,便于自定义指令中应用import './index.css'bind(el, binding) { ...... loadChild.className = "loadClass";}
这样的话,className
的款式,能够在引入的同级目录下的./index.css
文件中设置了,loadClass
款式如下:
.loadClass { /* 宽高百分百 */ position: absolute; top: 0; bottom: 0; left: 0; right: 0; /* 默认背景色和色彩 */ background-color: rgba(255, 255, 255, 0.99); color: #0b6ed0; /* 透明度过渡应用搭配display:none; */ opacity: 0.8; transition: all 0.3s; /* 居中 */ display: flex; align-items: center; justify-content: center;}
留神,加载中成果开启和隐没,不必应用vue
自带的过渡组件transition
,咱们能够应用透明度
搭配搭配display:none;
去设置
留神,加载中要以父元素为边界去管制,可不能满屏加载哦
而后初始化的时候,看看v-load
绑定的值是true
还是false
,同时加上一个用于暗藏的类名:load-hide
。再把这个加载中的dom
元素追加到指标父元素身上。
loadChild.classList.add('load-hide') // 增加类名target.appendChild(loadChild); // 追加加载中子元素/* 通过透明度实现过渡动画 */.load-hide { opacity: 0;}
这样的话,初始化的加载中就做好了。v-load
绑定的值是false
的时,就暗藏之
实现步骤三:当组件更新时,去增加或移除这个load-hide类名
componentUpdated(el, binding, vnode, oldVnode) { let flag = binding.value let loadChild = el.querySelector('.loadClass') if (flag) { // v-load绑定的值为true,就移除这个类名,就能看到了 loadChild.style.display = 'flex' setTimeout(() => { loadChild.classList.remove('load-hide') }, 0); } else { // 绑定的值为false时,再增加这个类名,同时暗藏dom loadChild.classList.add('load-hide') setTimeout(() => { loadChild.style.display = 'none' }, 360); } },
留神上述代码中为啥不间接暗藏,而是应用定时器缩短360毫秒
再去暗藏,因为笔者设置的加载dom
的过渡工夫是0.3秒
,即要等到透明度过渡完了当前,再暗藏加载中dom
,这样看着就天然一些了。
.loadClass { transition: all 0.3s; }
到这里,咱们的v-load
自定义指令的加载中成果,就初步实现了。不过性能有点少,自定义加载中我还想,去动态控制:
- 自定义加载图标名
- 自定义加载文字
- 自定义加载文字色彩
- 自定义加载背景色
那这样怎么办呢?
实现步骤四:优化自定义指令,反对传入更多的参数
此时,我的v-load
自定义指令,就不必绑定一个布尔值了。能够思考绑定一个对象啊,通过管制这个对象的具体值,来动态控制加载中的成果。
- 原来自定义指令绑定:
v-load = loading
//typeof loading == 'boolean'
- 当初自定义指令绑定:
v-load = loading2
//typeof loading2 == 'object'
<div class="box" v-load="loading2">222</div>// 如果想要有更多的配置项,就传一个对象,留神要指定字段loading2: { value: true, icon: "el-icon-eleme", // 自定义加载图标名 text: "客官稍等哦...", // 自定义加载文字 color: "red", // 自定义加载文字色彩 bgColor: "#baf", // 自定义加载背景色}
传参指定相应字段,自定义指令中接参,就要在相干的钩子中去接管并解决这些参数。
如何解决这些参数?
- v-load绑定的值的类型的判断,是布尔值,还是对象,执行不同的操作
- 应用原生js的形式去,发明dom元素、给dom元素指定类名(或增加删除类名)
- 思考到性能缘故,能够应用文档碎片优化
document.createDocumentFragment()
- 最初丢入遮罩层dom外部即可
残缺代码
自定义指令款式文件index.css
.loadClass { /* 宽高百分百 */ position: absolute; top: 0; bottom: 0; left: 0; right: 0; /* 默认背景色和色彩 */ background-color: rgba(255, 255, 255, 0.99); color: #0b6ed0; /* 透明度过渡应用搭配display:none; */ opacity: 0.8; transition: all 0.3s; /* 禁止文字抉择 */ user-select: none; display: flex; align-items: center; justify-content: center;}/* 通过透明度实现过渡动画 */.load-hide { opacity: 0;}.loadClass>i { margin-right: 4px;}
自定义指令的js文件index.js
留神,自定义指令还须要注册一下能力应用哦
// 引入拆分的款式,便于自定义指令中应用import './index.css'export default { // 初始化绑定dom钩子函数 bind(el, binding) { const target = el; // 传参类型判断变量管制 let flag; let isObj; if (typeof binding.value == 'boolean') { flag = binding.value isObj = false } if (typeof binding.value == 'object') { flag = binding.value.value isObj = true } // 有dom元素才去做操作 if (target) { // 父元素绝对定位 target.style.position = "relative"; // 子元素遮罩层局部 let loadChild = document.createElement("div"); loadChild.className = "loadClass"; // 创立文档碎片性能略微优化一点点 let fragment = document.createDocumentFragment() // 孙子元素1加载图标局部 let iSun = document.createElement("i"); iSun.className = isObj ? binding.value.icon : "el-icon-loading"; // 孙子元素2文字提醒局部 let spanSun = document.createElement("span"); spanSun.innerHTML = isObj ? binding.value.text : '加载中...' // 应用文档碎片将iSun和spanSun装起来 fragment.appendChild(iSun); fragment.appendChild(spanSun); // 将文档碎片丢入子元素遮罩层内 loadChild.appendChild(fragment); // 款式判断设置 if (isObj) { loadChild.style.color = binding.value.color loadChild.style.backgroundColor = binding.value.bgColor } // 若为false,就暗藏 if (!flag) { loadChild.classList.add('load-hide') loadChild.style.display = 'none' } // 父元素增加子元素遮罩层应用 target.appendChild(loadChild); } }, // dom组件更新操作控制显示和暗藏 componentUpdated(el, binding, vnode, oldVnode) { let flag = typeof binding.value == 'boolean' ? binding.value : binding.value.value let loadChild = el.querySelector('.loadClass') if (flag) { loadChild.style.display = 'flex' setTimeout(() => { loadChild.classList.remove('load-hide') }, 0); } else { loadChild.classList.add('load-hide') setTimeout(() => { loadChild.style.display = 'none' }, 360); } },}
应用自定义load指令的中央
<template> <div> <h3>指令形式加载中...</h3> <br /> <button @click="loadFn">点一下</button> <br /> <br /> <el-table v-load="loading" border :data="tableData" style="width: 80%"> <el-table-column prop="name" label="姓名"></el-table-column> <el-table-column prop="age" label="年龄"></el-table-column> <el-table-column prop="home" label="他乡"></el-table-column> <el-table-column prop="like" label="喜好"></el-table-column> </el-table> <br /> <div class="box" v-load="loading">111</div> <br /> <div class="box" v-load="loading2">222</div> </div></template><script>export default { name: "myLoadName", data() { return { // 自定义指令形式,默认绑定的值是布尔值 loading: true, // 如果想要有更多的配置项,就传一个对象,留神要指定字段 loading2: { value: true, icon: "el-icon-eleme", // 自定义加载图标名 text: "客官稍等哦...", // 自定义加载文字 color: "red", // 自定义加载文字色彩 bgColor: "#baf", // 自定义加载背景色 }, tableData: [ { name: "孙悟空", age: 500, home: "花果山水帘洞", like: "桃子", }, { name: "猪八戒", age: 88, home: "高老庄", like: "肉包子", }, { name: "沙和尚", age: 1000, home: "通天河", like: "游泳", }, ], }; }, methods: { loadFn() { this.loading = !this.loading; this.loading2.value = !this.loading2.value; }, },};</script><style lang='less' scoped>.box { width: 160px; height: 80px; border: 2px solid #666; box-sizing: border-box;}</style>
大家能够去GitHub仓库中看一下笔者的代码,除了自定义指令外,还有别的笔者仿写的组件,或者对大家有一点点的帮忙^_^
欢送大家不吝赐教,不吝star
A good memory is better than a bad pen. Write it down......