小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
Decorator 的语法还没有通过提案,所以项目中很少用。不过最近刚好有一个需求用到了。
什么是装饰器
装饰器是一种函数,写成@ + 函数名。它可以放在类和类方法的定义前面。
我理解装饰器就是一个函数生成器,是一种高阶函数。
装饰器可以用来修饰类、方法,装饰器可以嵌套使用,也可以传入参数。具体语法可以参考 ECMAScript 6 入门-装饰器。
具体需求
在写业务需求时,有很多操作都需要二次确认,比如删除一个文件之前,需要加入一个确认窗口。
因为用到的是 Vue2.x + Element UI,所以具体的函数代码大概是这个样子:
deleteFile(data) {
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
type: 'warning'
}).then(() => {
// 删除文件操作
}).catch(() => {});
}
二次确认在很多危险操作都需要,所以每个函数都加一遍确认部分的代码,感觉有点冗余,于是想到了使用注释器将 confirm 部分提出去。代码如下:
import { MessageBox } from 'element-ui';
function confirmation(target, name, descriptor) {
let oldValue = descriptor.value;
descriptor.value = function(...args) {
MessageBox.confirm('此操作将永久删除该文件, 是否继续?', '提示')
.then(oldValue.bind(this, ...args))
.catch(() => {});
};
return descriptor;
}
这样只需要在需要二次确认的函数上加一个 @confirmation 即可:
@confirmation
deleteFile(data) {
// 删除文件操作
}
不过不同的操作需要的提示往往不一样,那就在注释器上加一个参数。
import { MessageBox } from 'element-ui';
export function confirmation(message) {
return function(target, name, descriptor) {
let oldValue = descriptor.value;
descriptor.value = function(...args) {
MessageBox.confirm(message, '提示')
.then(oldValue.bind(this, ...args))
.catch(() => {});
};
return descriptor;
}
}
使用代码
@confirmation('此操作将永久删除该文件, 是否继续?')
deleteFile(data) {
// 删除文件操作
}
相关配置
我的项目是通过 Vue Cli 创建,需要添加 ESlint 配置。
"parserOptions": {
// ...
"ecmaFeatures": {
"legacyDecorators": true
}
}