引自 https://www.tslang.cn/docs/handbook/decorators.html
类装饰器
/**
*
* @param constructor 构造函数
* @returns 如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明
*/
function classDecorator<T extends { new (...args: any[]): {} }>(constructor: T) {
return class extends constructor {
newProperty = "new property";
hello = "override";
};
}
@classDecorator
export class Greeter {
property = "property";
hello: string;
constructor(m: string) {
this.hello = m;
}
}
方法装饰器
/**
*
* @param value 传进来的参数
* @returns
*/
function enumerable(value: boolean) {
/**
* @param target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
* @param propertyKey 成员的名字(函数名)
* @param descriptor 成员的属性描述符(
* configurable: true
enumerable: false
value: ƒ greet()
writable: true
* )
*/
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
export class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@enumerable(false)
greet() {
return "Hello, " + this.greeting;
}
}
访问器装饰器
function configurable(value: boolean) {
/**
* @param target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
* @param propertyKey 成员的名字(属性名)
* @param descriptor 成员的属性描述符(
* configurable: true
enumerable: false
get: ƒ ()
set: undefined
)
*/
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.configurable = value;
};
}
export class Point {
private _x: number;
private _y: number;
constructor(x: number, y: number) {
this._x = x;
this._y = y;
}
@configurable(false)
get x() {
return this._x;
}
@configurable(false)
get y() {
return this._y;
}
}
属性装饰器
// 这里用到了reflect-metadata(元数据)
// 相关介绍见 https://jkchao.github.io/typescript-book-chinese/tips/metadata.html
import "reflect-metadata";
// ES6引入的数据类型 表示独一无二的值,最大的用法是用来定义对象的唯一属性名
const formatMetadataKey = Symbol("format");
/**
*
* @param formatString 装饰器参数
* @returns 元数据添加
*/
function format(formatString: string) {
return Reflect.metadata(formatMetadataKey, formatString);
}
/**
*
* @param target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
* @param propertyKey 成员的名字
* @returns 元数据读取
*/
function getFormat(target: any, propertyKey: string) {
/**
* @param metadataKey A key used to store and retrieve metadata
* @param target The target object on which the metadata is defined.
* @param propertyKey The property key for the target.
*/
return Reflect.getMetadata(formatMetadataKey, target, propertyKey);
}
export class Greeter {
// 为greeting属性添加元信息
@format("Hello, %s")
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
// 读取greeting的元信息
let formatString = getFormat(this, "greeting");
// 替换greeting元信息("Hello, %s")里的"%s"为greeting属性值
return formatString.replace("%s", this.greeting);
}
}
参数装饰器
@required装饰器添加了元数据实体把参数标记为必需的。
@validate装饰器把greet方法包裹在一个函数里在调用原先的函数前验证函数参数。
import "reflect-metadata";
const requiredMetadataKey = Symbol("required");
/**
*
* @param target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
* @param propertyKey 成员的名字("greet")
* @param parameterIndex 参数在函数参数列表中的索引(0)
*/
function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {
let existingRequiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyKey) || [];
existingRequiredParameters.push(parameterIndex);
Reflect.defineMetadata(requiredMetadataKey, existingRequiredParameters, target, propertyKey);
}
// 参照方法装饰器
function validate(target: any, propertyName: string, descriptor: PropertyDescriptor) {
let method = descriptor.value;
descriptor.value = function () {
let requiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyName);
if (requiredParameters) {
for (let parameterIndex of requiredParameters) {
if (parameterIndex >= arguments.length || arguments[parameterIndex] === undefined) {
throw new Error("Missing required argument.");
}
}
}
return method!.apply(this, arguments);
};
}
export class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@validate
greet(@required name: string) {
return name + " " + this.greeting;
}
}
// 输出 hello world
console.log(new Greeter("world").greet("hello"));
实例
使用elementui的message,在删除前提示
参考
https://www.cnblogs.com/wenruo/p/11984558.html
// decorators.ts
import { MessageBox } from "element-ui";
export function confirmation(message: string) {
return function (target: any, name: string, descriptor: PropertyDescriptor) {
let oldValue = descriptor.value;
descriptor.value = function (args: IArguments) {
MessageBox.confirm(message, "提示")
.then(oldValue.bind(this, args))
.catch(() => {});
};
return descriptor;
};
}
// test.vue
import { confirmation } from "./decorators";
@confirmation("此操作将永久删除该文件, 是否继续?")
private deleteFile(data: any) {
console.log(data + "deleted");
}