装饰器工具函数[持续更新]

TypeScript中的装饰器

随着TypeScript和ES6里引入了类,在一些场景下我们需要额外的特性来支持标注或修改类及其成员。 装饰器(Decorators)为我们在类的声明及成员上通过元编程语法添加标注提供了一种方式。

使用

更新tsconfig.json,开启装饰器实验功能

1
2
3
4
5
6
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true
}
}

在项目中,在方法或属性前一行通过@[装饰器名称] 加入装饰器

例如

1
2
3
4
5
6
7
class Submit {

private onClick(): void { // 这是一个Submit类下普通的方法但是我们现在想为这个onclick方法加入防抖功能
console.log('submit')
}

}

加入装饰器后, 这种非入侵式的加入功能,和设计模式中装饰器模式非常契合!

1
2
3
4
5
6
7
8
class Submit {

@Debounce() // 此处是防抖装饰器
private onClick(): void {
console.log('submit')
}

}

需要知道

目前浏览器中并不直接支持装饰器的语法,JavaScript中的装饰器也还只在提案阶段。而前端大佬阮一峰也只对之前旧提案的语法进行了解释[阮一峰的装饰器教程]

因此,TypeScirpt中装饰器在编译后看不到任何@等特殊语法,而是将装饰器和装饰的目标生成一个混合的方法或属性,然后使用Object.defineProperty()来重新定义到原有的方法和属性。

著名的工具函数第三库lodash也发布了装饰器版本,其中包含了大量的工具装饰器lodash-decorators

装饰器方法【持续更新】

该列表中将会持续更新一些自己编写的装饰器方法(可能lodash中已经存在,但也可能没有),作为方法仓库

Debounce 防抖

防止抖动

  • delay 延迟
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* [装饰器]防止抖动
* @param delay 延迟
*/
export function Debounce(delay = 300): any {
return (
target: Object,
propertyKey: string,
propertyDecorator: PropertyDescriptor
): PropertyDescriptor => {
const methods = propertyDecorator.value;
let timer: number | null = null;
propertyDecorator.value = function(...args: any): void {
timer && clearTimeout(timer);
timer = setTimeout(methods.bind(this, ...args), delay);
};
return propertyDecorator;
};
}

ClickOutside 处理点击某元素外的事件

处理点击指定元素之外的事件,配合Vue使用,推荐在mounted及以后的生命周期中执行

  • offscaleElRef 指定元素的ref值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* 处理点击指定元素之外的工具,推荐在mounted及以后的生命周期中执行
* @param offscaleElRef 指定元素的ref值
*/
export function ClickOutside(offscaleElRef: string): any {
return (
target: Object,
propertyKey: string,
propertyDecorator: PropertyDescriptor
): PropertyDescriptor => {
const methods = propertyDecorator.value;
propertyDecorator.value = function(this: any, ...args: any): void {
const offscaleEl = this.$refs[offscaleElRef];
if (offscaleEl && offscaleEl.contains) {
document.addEventListener('click', event => {
if (!event || !event.target) return;
const clickEl = event.target as HTMLElement;
const clickSelf = offscaleEl.contains(clickEl);
if (!clickSelf) {
methods.call(this, ...args);
}
});
}
};
return propertyDecorator;
};
}
0%