背景说明
前端在控制遮罩的时候往往会在异步函数中的各种地方去调用,造成函数耦合和维护困难的问题。
解决办法
解决办法我想到的有两种:
- 通过在请求拦截器中对每一个或特定的请求开启全局的遮罩,这种方法相对简单粗暴这里不做研究
- 使用装饰器模式单独处理遮罩的开关和变量,并将方法模块化
使用装饰器模式
定义:装饰器模式能够很好的对已有的功能进行拓展,这样不会更改原有的代码,对其他的业务产生影响,这方便我们在较少改动下对软件功能进行拓展
例子:在一个函数上添加一个前置函数
创建JS文件定义前置函数(命名随意)
Function.prototype.befor=function(beforFn){
var _this=this
return function(){
beforFn.apply(this,arguments)
return _this.apply(this,arguments)
}
}
在基础函数上使用前置函数
function test(){
console.log("2222222")
return 1111111
}
var test1=test.before(function(){
console.log("000000")
})
console.log(test1())//输出返回值111111,控制台输出000000和2222222
以上就是一个简单的前置函数
但是我们要控制遮罩就必须在基础函数执行前和执行完毕后,去对控制遮罩的变量进行修改
所以我们对前置函数稍加修改就可以对遮罩变量进行修改
const loadingList = reactive({});
Function.prototype.loading = async function (param) {
loadingList[param] = true
await this.apply(this)
loadingList[param] = false
}
然后为了能将我们的函数进行导出我们在这个函数的外面再嵌套一层函数
export const loadingList = reactive({});
export function load() {
return Function.prototype.loading = async function (param) {
loadingList[param] = true
await this.apply(this)
loadingList[param] = false
}
}
这样我们最基本的模块化就做好了在页面中import即可使用
import {loadingList,load} from "路径"
<div v-loading="loadingList['名字']">
<button @click="XXX.loading('名字')">
</div>
onMounted(() => {
//挂载遮罩控制函数
load()
})
//基础函数需要是异步函数
async function XXX() {
await ...
}
单例问题
但是如果有多个页面引用了这个函数我们会发现loadingList这个变量是公用的,容易出现传入变量名重复的问题
所以为了解决单例问题
我们使用类来封装
import { reactive } from "vue";
class Load {
constructor() {
this.loadingList = reactive({});
}
load() {
let _this=this
return Function.prototype.loading = async function (param) {
console.log(_this.loadingList[param])
_this.loadingList[param] = true
await this.apply(this)
_this.loadingList[param] = false
}
}
}
export default new Load
完整代码
//非单例模式
import { reactive } from "vue";
class Load {
constructor() {
this.loadingList = reactive({});
}
createLoadFunction() {
let _this = this
/**
* @param param 控制遮罩名
* @param flag 是否开启超时控制
* @param timeOut 设置超时时间
*/
return Function.prototype.loading = async function (param, flag = 0, timeOut = 0) {
if (Object.prototype.toString.call(this) !== '[object AsyncFunction]' && !this.toString().includes("return _regenerator.default.async(function"))
throw "基本函数为非异步函数"
if (!param) throw "未传入遮罩名"
if (flag) {
setTimeout(() => {
_this.loadingList[param] = true
}, timeOut)
} else {
_this.loadingList[param] = true
}
await this.apply(this)
_this.loadingList[param] = false
}
}
}
export default new Load
import load from '@/views/test/memory-monitor/loading-controller.js'
<div v-loading="loadingList['名字']">
<button @click="XXX.loading('名字')">
</div>
onMounted(() => {
//挂载遮罩控制函数
load.createLoadFunction()
})
//遮罩控制列表
const loadingList = load.loadingList
//基础函数需要是异步函数
async function XXX() {
await ...
}