vue3创建全局的加载组件
vue
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
项目地址:https://gitcode.com/gh_mirrors/vu/vue
免费下载资源
·
最近在用vue3开发H5,开发了一个全屏加载的组件,组件开发很容易,但是需要每次引入就很麻烦了,所以像像elementUI那样,用可以直接在script中调用组件的方式来实现,由此开始这篇文章。
1、开发加载组件
这个没什么好说的,自己开发一个加载组件,样式自定义,下面是一个简单的例子:
// base-loading.vue
<template>
<view class="base-loading">
<view>
<view class="triple-spinner"></view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const props = defineProps({
remove: {
type: Function,
default: null
},
})
// 销毁组件
const hide = () => {
console.log('调用删除');
props.remove()
}
defineExpose({
hide
})
</script>
<style lang="scss" scoped>
.base-loading {
width: 100%;
height: 100vh;
background-color: rgba(255, 255, 255, .8);
position: fixed;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
}
.triple-spinner {
display: block;
position: relative;
width: 125px;
height: 125px;
border-radius: 50%;
border: 4px solid transparent;
border-top: 4px solid #FF5722;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
.triple-spinner::before,
.triple-spinner::after {
content: "";
position: absolute;
border-radius: 50%;
border: 4px solid transparent;
}
.triple-spinner::before {
top: 5px;
left: 5px;
right: 5px;
bottom: 5px;
border-top-color: #FF9800;
-webkit-animation: spin 3s linear infinite;
animation: spin 3.5s linear infinite;
}
.triple-spinner::after {
top: 15px;
left: 15px;
right: 15px;
bottom: 15px;
border-top-color: #FFC107;
-webkit-animation: spin 1.5s linear infinite;
animation: spin 1.75s linear infinite;
}
@-webkit-keyframes spin {
from {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes spin {
from {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
</style>
2、将组件绑定到Vue3全局属性上
在vue2中,我们通常使用Vue.extend()来实现用JS函数这种方式来调用组件的效果,在Vue3中已经去除了extend方法,但是Vue3中也给了解决方案,那就是createApp函数,当然,用createVNode和render函数组合也可以实现,而且应该更灵活,但这里就不做介绍了(因为还没研究哈哈)。
// index.ts,与banse-laoding.vue放在同一文件夹中,用于将组件挂载到vue上
import BaseLoading from "./base-loading.vue";
import { createApp } from 'vue'
let app = null
let mountNode = null
export default function CreateLoading(options : any) {
const dom = document.querySelector('my-base-loading')
if (!dom) {
mountNode = document.createElement('div')
mountNode.className = 'my-base-loading'
document.body.appendChild(mountNode)
} else {
app.unmount()
document.body.removeChild(mountNode)
}
app = createApp(BaseLoading, {
...options, remove() {
// 卸载已挂载的应用实例
if (app) {
app.unmount()
app = null
}
// 删除mountNode节点
if (mountNode) {
document.body.removeChild(mountNode)
// console.log('卸载dom节点');
mountNode = null
}
}
})
console.log('app实例', app);
return app.mount(mountNode)
}
// 此处是在组件上直接挂载方法,方便直接调用销毁组件的方法
CreateLoading.hide = (options : any) => CreateLoading(options).hide()
// 出口文件,可以将所有函数式组件放在一起抛出
import baseLoading from "./base-loading/index"
// const components = import.meta.glob( './components/**')
const components = {
showLoading: baseLoading
}
export default function (app : any) {
// 将函数组件定义到全局变量中,在vue中的script中通过proxy使用
Object.keys(components).forEach(key => {
app.config.globalProperties[`$${key}`] = components[key];
})
}
// 然后我们在main.ts中引入
import { createSSRApp } from 'vue'
import FC from '@/components/function/index.ts'
export function createApp() {
const app = createSSRApp(App)
app.use(FC)
return {
app
}
}
代码如上,这里有几点需要注意,我之前也搜过类似的实现方式,不过人家是拿全局的Toast组件来举例的,由于Toast组件是延时自动消失的,所以不用手动控制,那么这种情况下可以建立多个实例,反正最终都是组件内部去处理销毁实例的,但是全局加载组件一般是放在请求里的,请求结束后手动去结束,所以:
- 1、我们要对创建的组件实例和dom进行判断,保证同一时间只有一个实例存在;
- 2、要想手动控制加载组件的结束,我的实现方法时,调用组件的时候返回组件实例,这时候保存它,在想结束的地方用这个实例去调用它的结束方法;
所以在组件中使用该全局加载组件的方式如下:
// 以下仅为setup中部分代码
import { getCurrentInstance } from 'vue
const proxy = getCurrentInstance().proxy
const getList = async () => {
const laoding = proxy.$showLoading()
// 等待后端接口请求结束
await getListApi()
laoding.hide()
}
注意:上述方法只能在组件中使用,如果想在js文件中使用,比如在封装好的http请求类中使用,那么getCurrentInstance()方法是获取不到实例的,这种情况下我们可以直接导入这个组件,如下:
// 假设下面是一个封装好的请求类
import Loading from '@/components/function/base-loading/index.ts' // 直接引入index文件
let Baseloading = null
class ZWRequest {
instance = {}
constructor(config) {
this.instance.timeout = 60000
this.instance = Object.assign({}, this.instance, config)
// console.log('----------------------', this.instance);
}
request(config) {
if (Baseloading) {
Baseloading.hide()
}
Baseloading = Loading()
return new Promise((resolve, reject) => {
const instance = {
...this.instance,
...config
}
uni.request({
...instance,
// 接口调用成功时触发
success: (res) => {
// console.log('结果:', res);
if (!res.data.flag) {
let message = ''
switch (res.data.code) {
case 400001:
message = '登录失效'
break
default:
message = res.data.message
}
console.log('错误信息', message);
uni.showModal({
title: '提示',
content: message,
success: (data) => {
if (res.data.code == 400001) {
console.log('登录失效');
backIndex()
}
}
})
reject()
} else {
resolve(res)
}
},
// 接口调用失败时触发
fail: (err) => {
console.log('接口调用失败的返回', err);
uni.showModal({
content: '网络异常,请稍后重试!'
})
reject(err)
},
// 接口调用结束时触发
complete: (res) => {
console.log('在此处去除加载组件');
Baseloading.hide()
// console.log('接口调用结束', res);
}
})
})
}
......
}
写在最后:由于是使用了document,所以在小程序中式不适用的。
GitHub 加速计划 / vu / vue
207.55 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5
* chore: fix link broken
Signed-off-by: snoppy <michaleli@foxmail.com>
* Update packages/template-compiler/README.md [skip ci]
---------
Signed-off-by: snoppy <michaleli@foxmail.com>
Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891
Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
更多推荐
已为社区贡献2条内容
所有评论(0)