在项目中,是否遇到一些特殊场景,需要自定义一些全局的loading 或者 弹窗信息等。此时,扩展实例构造器就派上了用场!
在vue2中,我们通常是使用vue.extend + $mount实现; 直接贴上官网代码吧!
<div id="mount-point"></div>
// 创建构造器
var Profile = Vue.extend({
template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
data: function () {
return {
firstName: 'Walter',
lastName: 'White',
alias: 'Heisenberg'
}
}
})
// 创建 Profile 实例,并挂载到一个元素上。
new Profile().$mount('#mount-point')
结果如下:
<p>Walter White aka Heisenberg</p>
在vue3中的实现呢? 我们查看vue3 API文档可以发现,api中已经没有extend了。取而代之的使用createApp实现。
以下实现一个简单的全局loading组件:
Loading组件实现:Loading.vue
<template>
<div class="loader">
<div class="loader-inner">
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
const show = ref<boolean>(true);
const msg = "通过instance可以读取到的变量";
//使用了setup语法糖 需要手动暴露
defineExpose({
show,
msg,
});
</script>
<style lang="scss" scoped>
.loader {
background: rgba(0, 0, 0, 0.7);
bottom: 0;
left: 0;
overflow: hidden;
position: fixed;
right: 0;
top: 0;
z-index: 99999;
}
.loader-inner {
bottom: 0;
height: 60px;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
width: 100px;
}
.loader-line-wrap {
animation: spin 2000ms cubic-bezier(0.175, 0.885, 0.32, 1.275) infinite;
box-sizing: border-box;
height: 50px;
left: 0;
overflow: hidden;
position: absolute;
top: 0;
transform-origin: 50% 100%;
width: 100px;
}
.loader-line {
border: 4px solid transparent;
border-radius: 100%;
box-sizing: border-box;
height: 100px;
left: 0;
margin: 0 auto;
position: absolute;
right: 0;
top: 0;
width: 100px;
}
.loader-line-wrap:nth-child(1) {
animation-delay: -50ms;
}
.loader-line-wrap:nth-child(2) {
animation-delay: -100ms;
}
.loader-line-wrap:nth-child(3) {
animation-delay: -150ms;
}
.loader-line-wrap:nth-child(4) {
animation-delay: -200ms;
}
.loader-line-wrap:nth-child(5) {
animation-delay: -250ms;
}
.loader-line-wrap:nth-child(1) .loader-line {
border-color: hsl(0, 80%, 60%);
height: 90px;
width: 90px;
top: 7px;
}
.loader-line-wrap:nth-child(2) .loader-line {
border-color: hsl(60, 80%, 60%);
height: 76px;
width: 76px;
top: 14px;
}
.loader-line-wrap:nth-child(3) .loader-line {
border-color: hsl(120, 80%, 60%);
height: 62px;
width: 62px;
top: 21px;
}
.loader-line-wrap:nth-child(4) .loader-line {
border-color: hsl(180, 80%, 60%);
height: 48px;
width: 48px;
top: 28px;
}
.loader-line-wrap:nth-child(5) .loader-line {
border-color: hsl(240, 80%, 60%);
height: 34px;
width: 34px;
top: 35px;
}
@keyframes spin {
0%,
15% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
</style>
组件实例构造器实现:Loading.ts
import { Component, createApp } from "vue";
import Loading from './index.vue';
let instance: any, unmount: () => void;
function mountComponent(rootComponent: Component) {
const app = createApp(rootComponent);
const root = document.createElement('div');
document.body.append(root);
return {
instance: app.mount(root),
unmount: () => {
document.body.removeChild(root)
}
}
}
// 创建一个loading组件
export function $showLoading() {
({ instance, unmount } = mountComponent(Loading));
console.log(instance);
}
// 销毁loading组件
export function $hiddenLoading() {
instance && unmount();
}
好了,一个全局的Loading组件定义好了
Loading组件使用:index.vue
// 导入loading
import { $showLoading, $hiddenLoading } from "@/Loading.ts";
onMounted(async () => {
// 使用loading组件
$showLoading();
setTimeout(() => {
// 卸载loading组件
$hiddenLoading();
}, 3000);
})
注意:loading方法使用,要在生命周期函数中使用,或者准确的说是在已挂载Dom的生命周期函数中使用,否则会出现报错!!!
以上是个人理解,也有一些借鉴!如有错误,请及时指出!