Vue JS中如何将Spinner功能封装到服务层无需逐页引入组件
实现方案
完全可以实现,核心思路是通过Vue的编程式渲染API将Spinner组件动态挂载到全局DOM节点上,不需要在页面/组件内显式引入,再把显隐方法暴露给你的Service类调用即可,不需要引入第三方加载库。
你可以先给Spinner的modal容器补充基础样式,确保加载动画居中、层级足够:
<template> <div class="spinner-modal" v-if="start"> <div class="spinner-border text-info" role="status" style="width: 3rem; height: 3rem;"> <span class="visually-hidden">Loading...</span> </div> </div> </template> <script> export default { name: 'Spinner', props: { start: { type: Boolean, default: true, }, }, } </script> <style scoped> .spinner-modal { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(255,255,255,0.7); display: flex; align-items: center; justify-content: center; z-index: 9999; } </style>
步骤1:封装全局Spinner控制工具
Vue3版本
新建spinnerService.js文件,代码如下:
// spinnerService.js import { createApp } from 'vue' import Spinner from './Spinner.vue' // 导入你修改好的Spinner组件 let spinnerInstance = null let mountNode = null // 并发请求计数器,避免多请求时加载动画提前消失 let requestCount = 0 export const showSpinner = () => { requestCount++ if (spinnerInstance || requestCount > 1) return // 创建挂载节点 mountNode = document.createElement('div') document.body.appendChild(mountNode) // 生成组件实例并挂载 const app = createApp(Spinner, { start: true }) spinnerInstance = app.mount(mountNode) } export const hideSpinner = () => { requestCount-- if (requestCount > 0) return if (!spinnerInstance || !mountNode) { requestCount = 0 return } // 卸载组件并销毁节点 spinnerInstance.unmount() document.body.removeChild(mountNode) spinnerInstance = null mountNode = null requestCount = 0 }
Vue2版本
如果是Vue2项目,spinnerService.js调整为如下写法:
// spinnerService.js Vue2版本 import Vue from 'vue' import Spinner from './Spinner.vue' let spinnerInstance = null let mountNode = null let requestCount = 0 export const showSpinner = () => { requestCount++ if (spinnerInstance || requestCount > 1) return const SpinnerConstructor = Vue.extend(Spinner) mountNode = document.createElement('div') document.body.appendChild(mountNode) spinnerInstance = new SpinnerConstructor({ propsData: { start: true } }).$mount(mountNode) } export const hideSpinner = () => { requestCount-- if (requestCount > 0) return if (!spinnerInstance || !mountNode) { requestCount = 0 return } spinnerInstance.$destroy() document.body.removeChild(mountNode) spinnerInstance = null mountNode = null requestCount = 0 }
步骤2:在服务封装类中调用
改造你的Service请求封装,在请求前后调用对应方法即可,哪怕是路由beforeEnter钩子中调用的请求也能正常触发加载动画:
// 你的Service封装文件 import { showSpinner, hideSpinner } from './spinnerService' const Service = { async getList() { showSpinner() try { // 保留你原有请求逻辑 const res = await axios.get('/your/api/interface') return res.data } finally { // 无论请求成功/失败都隐藏加载动画 hideSpinner() } }, // 其余所有请求方法都可以按同样逻辑调用显隐方法 }
可选优化
可以给showSpinner增加300ms左右的延迟触发逻辑,如果请求耗时短于延迟时间则不显示加载动画,避免页面频繁出现闪烁的加载状态。
内容的提问来源于stack exchange,提问作者Laterneman
相关产品推荐
相关产品推荐

