编写vue3插件,实现一个全局满屏loading
插件 (Plugins) 是一种能为 Vue 添加全局功能的工具代码。
插件没有严格定义的使用范围,app.use(xxx)就是在使用插件了。
官方已经为我们总结出来了,插件发挥作用的常见场景主要包括以下几种:
- 通过
app.component()
和app.directive()
注册一到多个全局组件或自定义指令。
- 通过
app.provide()
使一个资源可被注入进整个应用
- 向
app.config.globalProperties
中添加一些全局实例属性或方法
常见并且为我们熟悉插件的有:app.use(router)
,app.use(pinia)
。
像element-plus中的loading全屏加载和message消息提示,都可封装为一个插件来使用。下面我将使用插件的方式,封装一个类似于element-plus中的Loading全屏加载插件。这个插件可以在多处地方使用,像页面加载、数据加载、用户操作等待响应这三种场景,我们都可以使用这个loading插件来提高用户体验。
Loading插件代码实现
首先在src目录的components下的目录新建Loading.vue和Loaidng.js两个文件。
Loading.vue为一个组件,里面放置loading效果实现,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
| <template> <!-- 遮罩效果 --> <div class="cover" v-if="showCover"> <span class="loader-3">Load ng</span> </div> </template>
<script setup> import { ref, reactive } from "vue"; //showCover为响应式,可以被组件watch监听 const showCover = ref(false); //控制显示 const handlerShow = () => showCover.value = true; //控制隐藏 const handlerHide = () => showCover.value = false; ;
//将变量或方法抛出,使外界可访问 defineExpose({ showCover, handlerHide, handlerShow, }); </script>
<style scoped> .cover { position: fixed; top: 0; bottom: 0; left: 0; right: 0; background: rgba(0, 0, 0, 0.4); z-index: 9; display: flex; align-items: center; justify-content: center; } .loader-3 { color: #42b983; position: relative; font-family: Arial, Helvetica, sans-serif; font-size: 48px; /* letter-spacing: 48px; */ letter-spacing: 4px; top: -50px; /* font-weight: bold; */ } .loader-3::before { content: ""; position: absolute; right: 70px; bottom: 10px; height: 28px; width: 5.15px; background: currentColor; animation: loaderL 1s linear infinite alternate; } .loader-3::after { content: ""; width: 10px; height: 10px; position: absolute; left: 125px; top: 2px; border-radius: 50%; background: #42b983; animation: animloader113 1s linear infinite alternate; }
@keyframes loaderL { 0% { box-shadow: 0 -6px, -122.9px -8px; } 25%, 75% { box-shadow: 0 0px, -122.9px -8px; } 100% { box-shadow: 0 0px, -122.9px -16px; } } @keyframes animloader113 { 0% { transform: translate(0px, 0px) scaleX(1); } 14% { transform: translate(-12px, -16px) scaleX(1.05); } 28% { transform: translate(-27px, -28px) scaleX(1.07); } 42% { transform: translate(-46px, -35px) scaleX(1.1); } 57% { transform: translate(-70px, -37px) scaleX(1.1); } 71% { transform: translate(-94px, -32px) scaleX(1.07); } 85% { transform: translate(-111px, -22px) scaleX(1.05); } 100% { transform: translate(-125px, -9px) scaleX(1); } } </style>
|
然后在Loading.js中导入Loading组件,注册组件,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| import Loading from './Loading.vue' import { createVNode, render } from 'vue'
export default { install(app) { const Vnode = createVNode(Loading) render(Vnode, document.body) app.config.globalProperties.$loading = { show: Vnode.component.exposed.handlerShow, hide: Vnode.component.exposed.handlerHide, showCover: Vnode.component.exposed.showCover } }, singleton: null, service({ isShow = false }) { if (this.singleton) return this.singleton.show() && this.singleton
let container = document.createElement('div') const vm = createVNode(Loading) render(vm, container); document.body.appendChild(container);
this.singleton = { show: vm.component.exposed.handlerShow, hide: vm.component.exposed.handlerHide } if (isShow) this.singleton.show()
return this.singleton }
}
|
要想使用这个插件,还需要到main.js中use一下
1 2 3
| import Loading from './components/Loading.js' ... app.use(Loading)
|
在App.vue中通过点击按钮触发loading效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <template> <div class="container"> <button @click="handlerShowLoading">触发loading</button> </div> </template>
<script setup> import { ref, getCurrentInstance, watch } from "vue";
//getCurrentInstance为组件实例,全局属性都会被挂载到实例上,通过proxy可以访问到全局属性 const { proxy } = getCurrentInstance();
const handlerShowLoading = () => { //触发loading加载 proxy.$loading.show(); //5秒后关闭loading setTimeout(() => { proxy.$loading.hide(); }, 5000); };
//使用watch可以监听loading暴露的响应式变量 watch( () => proxy.$loading.showCover.value, (newVal, oldVal) => { console.log(newVal); } ); </script>
|
最终效果图如下: