共计 5978 个字符,预计需要花费 15 分钟才能阅读完成。
网站成果演示: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……