记录--Vue自定义指令实现加载中效果v-load(不使用Vue.extend)

news2024/11/15 8:11:34

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

Vue自定义指令实现加载中效果v-load(不使用Vue.extend)

网站效果演示:ashuai.work:8888/#/myLoad

GitHub仓库地址代码:github.com/shuirongshu…

加载中思路分析

实现加载中效果,一般有两种方式:

  • 第一种是:搞一个load组件,然后使用Vue.extend()方法去继承一个加载组件去使用,比如笔者的这篇文章:juejin.cn/post/702172…
  • 第二种是:直接使用指令去在需要加载的dom上去创建一个加载中的dom元素,并指定相应的样式即可。本篇文章说的是第二种。

我们先看一下效果图

v-load效果图

v-load.gif

实现步骤一:加上自定义指令

假设我有一个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元素。

关于自定义指令的入门基础知识可以看官方文档,或者参见笔者之前的关于自定义指令的文章:juejin.cn/post/702960…

实现步骤二:给目标元素创建一个子元素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>

本文转载于:

https://juejin.cn/post/7182375025368891429

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/400975.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

双馈风力发电机-900V直流混合储能并网系统MATLAB仿真

MATLAB2016b主体模型&#xff1a;双馈感应风机模块、采用真实风速数据。混合储能模块、逆变器模块、转子过电流保护模块、整流器控制模块、逆变器控制模块。直流母线电压&#xff1a;有功、无功输出&#xff08;此处忘记乘负一信号输出&#xff09;&#xff0c;所以是负的。蓄电…

鉴源论坛 · 观模丨模型检查综述

作者 | 李建文 华东师范大学软件工程学院博导 版块 | 鉴源论坛 观模 01 模型检查的历史 模型检查是一种起源于20世纪70年代末的形式化验证技术。该技术最初由Edmund M. Clarke、E. Allen Emerson和Joseph Sifakis提出&#xff0c;他们因在模型检查领域的贡献而获得了2007年的…

无监督循环一致生成式对抗网络:PAN-Sharpening

Unsupervised Cycle-Consistent Generative Adversarial Networks for Pan Sharpening &#xff08;基于无监督循环一致生成式对抗网络的全色锐化&#xff09; 基于深度学习的全色锐化近年来受到了广泛的关注。现有方法大多属于监督学习框架&#xff0c;即对多光谱&#xff0…

【Java闭关修炼】SpringBoot项目-贪吃蛇对战小游戏-配置git环境和项目创建

【Java闭关修炼】SpringBoot项目-贪吃蛇对战小游戏-配置git环境和项目创建项目的逐步细分配置git环境创建项目后端前后端不分离写法-url访问路径解析资源安装vuevue文件后端解析数据发送到前端页面解析出来项目的逐步细分 匹配界面&#xff1a;需要用微服务实况直播&#xff1…

Lesson 9.1 集成学习的三大关键领域、Bagging 方法的基本思想和 RandomForestRegressor 的实现

文章目录一、 集成学习的三大关键领域二、Bagging 方法的基本思想三、RandomForestRegressor 的实现在开始学习之前&#xff0c;先导入我们需要的库&#xff0c;并查看库的版本。 import numpy as np import pandas as pd import sklearn import matplotlib as mlp import sea…

Flink学习-单词统计WordCount

WordCount&#xff08;流处理&#xff09;通过socket数据源&#xff0c;去请求一个socket服务&#xff08;9999&#xff09;,得到数据流然后统计数据流中出现的单词及其个数1.创建一个编程入口&#xff0c;生成环境StreamExecutionEnvironment streamEnv StreamExecutionEnvir…

嵌入式Linux驱动开发(二)LED驱动

1. Linux下LED驱动原理 与裸机区别在于&#xff0c;编写驱动要符合linux驱动框架规范。裸机直接对寄存器物理地址进行读写&#xff0c;linux下需要经过MMU。 1.1 地址映射相关概念 1&#xff09;MMU&#xff08;Memory Manage Unit - 内存管理单元&#xff09;&#xff1a; …

新星计划·第四季·Python赛道报名入口 -〖你就是下一个新星〗

↓↓↓报名方式&#xff1a;&#xff08;下滑到本页面底部&#xff09;重要提醒&#xff1a;这里是新星计划第四季Python赛道报名入口&#xff0c;一经报名&#xff0c;不可更换。报名入口点击此处跳转 一、新星计划 新星计划是一个以发掘潜力新人、培养优质博主为目标的创作…

css3动画属性

边框弧度 border-radius:value // 四角 border-radius:value value // 左上右下 右上左下 border-radius:value value value value // 左上 右上 右下 左下 text-shadow:value value value color; // 水平 垂直 模糊度 颜色 线性渐变&#xff1a;background-image:linear-…

oracle的时间戳获取不含中文内容的方式

背景&#xff1a; 在做oracle的数据库同步时发现&#xff0c;创建的行级触发器获取表的时间戳数据时含有中文&#xff0c;导致入库时转义乱码&#xff0c;条件匹配失败。 调试过程&#xff1a; 写了一个declare脚本测试&#xff1a; declare --类型定义 cursor c_job IS sele…

java反射机制及其详解

反射反射机制反射调用优化有时候我们做项目的时候不免需要用到大量配置文件&#xff0c;就拿框架举例&#xff0c;通过这些外部文件配置&#xff0c;在不修改的源码的情况下&#xff0c;来控制文件&#xff0c;就要用到我们的反射来解决 假设有一个Cat对象 public class Cat …

堆的应用(topk问题)

文章目录1.堆排序1.1代码实现2. TOP-K问题2.1原理2.2实例分析1.堆排序 堆排序即利用堆的思想来进行排序&#xff0c;总共分为两个步骤&#xff1a; 1.建堆 升序&#xff1a;大堆 降序&#xff1a;小堆 2.利用堆删除思想来排序 1.1代码实现 void Heapsort(int* a, int n) {f…

C#中通过HttpClient发送Post请求

C#中HttpClient进行各种类型的传输我们可以看到, 尽管PostAsync有四个重载函数, 但是接受的都是HttpContent, 而查看源码可以看到, HttpContent是一个抽象类那我们就不可能直接创建HttpContent的实例, 而需要去找他的实现类, 经过一番研究, 发现了, 如下四个:MultipartFormData…

系列一、AliyunOSS开通及使用

一、对象存储OSS服务开通及配置 1.1、开通OSS 1.2、进入管理控制台 1.3、控制台使用 1.3.1、创建Bucket 命名&#xff1a;20230309-oss 读写权限&#xff1a;公共读 1.3.2、上传默认头像 创建文件夹 avater&#xff0c;上传默认的用户头像 1.4、使用RAM子用户 1.4.1、添加…

设计模式3——结构型模式

结构型模式描述如何将类或对象按某种布局组成更大的结构&#xff0c;它分为类结构型和对象结构型模式&#xff0c;前者采用继承机制来组织接口和类&#xff0c;后者采用组合或聚合来组合对象。 由于组合关系或聚合关系比继承关系耦合度低&#xff0c;满足“合成复用原则”&…

哈希表的实现

哈希表概念 二叉搜索树具有对数时间的表现&#xff0c;但这样的表现建立在一个假设上&#xff1a;输入的数据有足够的随机性。哈希表又名散列表&#xff0c;在插入、删除、搜索等操作上具有「常数平均时间」的表现&#xff0c;而且这种表现是以统计为基础&#xff0c;不需依赖…

CMU15-445 Project.4总结

在线测试 Project #4 - Concurrency Control 以下是Project #4的网址&#xff0c;2022FALL的Project #4是实现并发控制&#xff0c;可以分为以下三个任务&#xff1a; 我们首先需要实现一个锁管理器&#xff0c;能够支持 READ_UNCOMMITED、READ_COMMITTED、REPEATABLE_READ…

layui表格合并

先看一下最终合并之后的效果&#xff0c;能对单选、复选框进行按照某一列的合并 最开始的解决方案来自于这篇博客介绍的方法&#xff1a;https://blog.csdn.net/guishifoxin/article/details/81480136 但是还是存在没能解决的问题。 在完善之后达到的效果&#xff1a; 一&…

移动硬盘格式化?想要恢复硬盘那就看这里!

案例&#xff1a;移动硬盘无法打开&#xff0c;提示格式化&#xff1f; “怎么办啊&#xff01;&#xff01;&#xff01;今天下午给同学重装系统&#xff0c;插上自己的移动硬盘&#xff0c;却发现读不出来&#xff0c;提示需要格式化&#xff01;里面有很多东西&#xff0c;…

第十四章 opengl之高级OpenGL(深度测试)

OpenGL深度测试深度测试函数深度值精度深度缓冲的可视化深度冲突防止深度冲突深度测试 前面我们渲染一个3D图片中运用了深度缓冲&#xff1a;防止被阻挡的面渲染到其他面的前面。 深度缓冲就像颜色缓冲(Color Buffer)&#xff08;储存所有的片段颜色&#xff1a;视觉输出&…