问题
因为业务要求,每个按钮点击时都要一个加载状态。我们知道使用 elementui 的 button 可以用 loading 变量,现在问题在于,如果一个页面有多少个按钮,就必须维护多少个 loading 变量,这样容易导致代码臃肿不易维护。
思路
事件委托(可行,不推荐)
需要给每个按钮加一个标志,同时需要额外的代码来判断点击事件来自哪个按钮。
网络请求拦截(不可行)
设想利用 axios 的拦截点击按钮发起的网络请求,但是我们无法知道点击事件来自哪个按钮,也无法控制按钮的 loading 结束状态。
扩展按钮组件(可行,推荐)
思路就是扩展 elementui 按钮组件,给每个按钮单独维护一个 loading 状态。
扩展按钮组件
自定义组件
import { Button } from "element-ui";
export default {
name: 'el-button-custom',
extends: Button, // 扩展 elementui 的按钮组件
data() {
return {
isLoading: false,
}
},
render(h) {
return h(Button, {
class: 'my-class',
attrs: this.$attr,
on: {
click: this.onClick // 绑定事件
},
props: {
// 传入 Button 定义的参数(这里的参数都扩展自 Button,所以不需要自己声明)
...this.$props,
// 传入需要维护的 loading 变量
loading: this.isLoading,
}
}, this.$slots.default)
},
methods: {
// 自定义绑定事件控制 loading 状态
onClick() {
let res = this.$listeners.click() // 调用事件处理函数
// 注意:事件处理函数必须返回一个 Promise 实例
if(res instanceof Promise) {
this.isLoading = true
res.finally(() => {
this.isLoading = false // 结束加载状态
})
}else { // 错误提示
throw Error('@click function should return a Promise instance.')
}
}
}
}
注册
Vue.component('el-button-custom', ElButtonCustom)
使用
<template>
<el-button-custom @click="onButton1">转账</<el-button-custom>
<el-button-custom @click="onButton2">交易</<el-button-custom>
<el-button-custom @click="onButton3">同步</<el-button-custom>
</template>
export default {
methods: {
async onButton1() { // 声明为 async
},
onButton2() {
return Promise.resolve(0) // 显式返回 Promise 实例
},
onButton3() {
return new Promise(resovle => resolve(0)) // 显式返回 Promise 实例
.then(() => {})
},
}
}