(一) 装饰器
- 类装饰器---应用于类构造函数上。
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
- 方法装饰器---应用到方法的属性描述符上
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@enumerable(false)
greet() {
return "Hello, " + this.greeting;
}
}
function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
- 访问器装饰器---应用于访问器的 属性描述符
- 属性装饰器
- 参数装饰器---明在一个参数声明之前
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@validate
greet(@required name: string) {
return "Hello " + name + ", " + this.greeting;
}
}
import "reflect-metadata";
const requiredMetadataKey = Symbol("required");
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: TypedPropertyDescriptor<Function>) {
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);
}
}
(二) Reflect Metadata
namespace Reflect {
// 用于装饰器
metadata(k, v): (target, property?) => void
// 在对象上面定义元数据
defineMetadata(k, v, o, p?): void
// 是否存在元数据
hasMetadata(k, o, p?): boolean
hasOwnMetadata(k, o, p?): boolean
// 获取元数据
getMetadata(k, o, p?): any
getOwnMetadata(k, o, p?): any
// 获取所有元数据的 Key
getMetadataKeys(o, p?): any[]
getOwnMetadataKeys(o, p?): any[]
// 删除元数据
deleteMetadata(k, o, p?): boolean
}
原理: WeakMap<any, Map<any, Map<any, any>>> weakMap.get(o).get(p).get(k)
(三) Nest
Controllers
(四) Tailwind CSS
样式简写 响应式
@apply 方法
配置文件自定义样式
编译注意的地方 purge
(五) 图床
亮点:删除上传途中无用的图片
- cachePic: 存储所有的图片
- dbPic:存储已经缓存到数据库的图片
- oldPic:存储将要被删除的图片
在业务层,用户上传图片后,将图片key值塞进 cachePic,在用户将表单信息持久化后,将图片key值 塞进 dbPic。
- 设置一个定时任务
const { bucketManager, bucket } = await this.qiNiuService.getManageToken()
// 清空交集
const nowDelSet = await this.cacheService.sinter(['cachePic', 'dbPic'])
for (let key of nowDelSet.values() ) {
this.cacheService.srem('cachePic', key)
this.cacheService.srem('dbPic', key)
this.cacheService.srem('oldPic', key)
}
const oldDelSet = await this.cacheService.smembers('oldPic')
// 先把旧的要删的集合的图片删了
if (oldDelSet) {
for (let key of oldDelSet.values() ) {
this.cacheService.srem('oldPic', key)
this.cacheService.srem('cachePic', key)
bucketManager.delete(bucket, key, function(err, respBody, respInfo) {
if (err) {
console.log(err);
//throw err;
} else {
console.log(respInfo.statusCode);
console.log(respBody);
}
});
}
}
// 比较缓存和数据库图片,找出要删的图片(包括用户可能即将用的),取补集
const newDelSet = await this.cacheService.sdiff('cachePic', 'dbPic')
// 如果有新的要删的图片,就存到旧的里,等待下一回删
if (newDelSet) {
for (let key of newDelSet.values() ) {
this.cacheService.sadd('oldPic', key)
}
}