vue自定义指令v-loading(vue2和vue3)

效果

vue自定义指令v-loading(vue2和vue3)_第1张图片

 

vue2写法

1. 目录结构:

vue自定义指令v-loading(vue2和vue3)_第2张图片

2. 代码实现 

/directives/loading/loading.vue   loading效果页面(此处使用的antd下面的组件,可自定义)





/directives/loading/loading.js(实现loading组件的插入及销毁)

import Vue from 'vue'
import Loading from './loading.vue'

const Mask = Vue.extend(Loading)

const toggleLoading = (el, binding) => {
    if (binding.value) {
        Vue.nextTick(() => {
            // 控制loading组件显示
            el.instance.visible = true
            // 插入到目标元素
            insertDom(el, el, binding)
        })
    } else {
        el.instance.visible = false
    }
}

const insertDom = (parent, el) => {
    // 给父元素加个定位,让loading元素定位
    el.style.position='relative';
    parent.appendChild(el.mask)
}

export default {
    bind: function (el, binding, vnode) {
        const mask = new Mask({
            el: document.createElement('div'),
            data() { }
        })
        el.instance = mask
        el.mask = mask.$el
        el.maskStyle = {}
        binding.value && toggleLoading(el, binding)
    },
    update: function (el, binding) {
        if (binding.oldValue !== binding.value) {
            toggleLoading(el, binding)
        }
    },
    unbind: function (el, binding) {
        el.style.position='';
        el.instance && el.instance.$destroy()
    }
}

/directives/loading/index.js(loading指令的注册)

import loading from './loading';
export default {
  install(Vue) {
    Vue.directive("loading", loading) // 全局loading
  }
}

3. 全局引入(main.js文件)

// 引入loading
import loading from './vue-tool/directives/loading' 
Vue.use(loading);

4. 使用

我是loading父元素(isLoading为控制loading展示的自定义变量)

vue3写法

1. 目录结构

vue自定义指令v-loading(vue2和vue3)_第3张图片

2. 代码实现  

/directives/loading/index.vue   loading效果页面(此处使用的antd下面的组件,可自定义)







/directives/loading/index.ts(实现loading组件的插入及销毁)


import {createApp, Directive } from 'vue';
import Loading from './index.vue';

export const loading: Directive = {
    mounted(el,binding){
        const app = createApp(Loading);
        const instance = app.mount(document.createElement('div'));
        el.instance = instance;
        if (binding.value) {
            appendEl(el);
        }
    },
    updated(el,binding) {
        if (binding.value !== binding.oldValue) {
            binding.value ? appendEl(el) : removeEl(el); 
        }
    },
};
// 插入元素
const appendEl = (el) =>{
    // 给父元素加个定位,让loading元素定位
    el.style.position='relative';
    el?.appendChild(el.instance.$el);
};
// 移除元素
const removeEl = (el) =>{
    el.style.position='';

    // 踩坑:el?.removeChild(el.instance.$el)->直接这样写会报错:Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.(要删除的节点不是此节点的子节点)
    // 解决:判断一下是否为此节点的子元素再移除(参考:https://www.freesion.com/article/2620879355/)
    let $el = el.instance.$el;
    if (el?.contains($el)) {
        el?.removeChild($el);
    }
};

/directives/index.ts

export * from './loading'

3. 全局引入(main.js文件)

// 循环注册指令
import * as directives from './tool/directives';
Object.keys(directives).forEach(key => {
  Vue.directive(key, (directives as { [key: string ]: Directive })[key]);
});

4. 使用 v-loading=“”

补充:a-spin为antd组件,显示不了的可以把a-spin部分替换为一个简单的loading效果组件,下面提供两种可直接使用的:

1. 效果1

vue自定义指令v-loading(vue2和vue3)_第4张图片



2. 效果2

vue自定义指令v-loading(vue2和vue3)_第5张图片



你可能感兴趣的:(vue.js,javascript,前端)