你可能不知道vue还能这样写(二)

702 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

前言

阅读这篇文章将学习到:

  1. vue-property-decorator的用法
  2. 装饰器模式的运用
  3. 父子组件传值和Computed的灵活搭配

前面我们讲过了vue-class-component的写法,搭配着class组件我们还需要学习属性装饰器,vue-property-decorator,利用这个装饰器我们能够简化大部分的操作;

@Prop装饰器

@Prop的参数类型为:

export interface PropOptions<T=any> {
  type?: PropType<T>;
  required?: boolean;
  default?: T | null | undefined | (() => T | null | undefined);
  validator?(value: T): boolean;
}

也就是说我们在用这个参数和我们写props对象是一样,属性都是相同的,而且还有属性提示;唯一不同的在后面,就是我们这里会产生两个类型系统,一个是vue的类型系统一个是ts的类型系统,前面的是vue类型系统后面是ts类型系统,vue的类型系统是在vue运行时给组件进行type check的,而这里的ts类型仅仅只能对我们的编码进行智能提示,其实两者结合才是一个完整的ts check

@Prop({type:Object}) propName!:object;

但是如果任何情况下我们都要写两份类型这未免太麻烦了;但是框架设计者已经考虑到这一点,简单数据类型我们可以直接在ts类型中声明不需要另写一份,vue也会进行type check

@Prop() propName!:string;
@Prop() propName!:number;
@Prop() propName!:boolean;

但是如果我们不写任何类型那么type check就是object类型,如果传其他类型则会进行错误提示

@Prop() propName;

@PropSync装饰器

@PropSync装饰器类似于v-bind.sync,主要用于子组件修改父组件传过来的值,它们的区别是什么?看下面的案例:

@PropSync('name', { type: String }) syncedName!: string
// 直接这样赋值就能修改父组件传递的props
this.syncedName = 'changed'

// 父组件
<A :propValue.sync="value"/>
// A组件需要通过methods去更新父组件这个value值
@Prop() propValue
click(){
    this.$emit('update:propValue', NaN)
}

实际上@PropSync借用了一个Computed将这个修改父组件值得methods封装起来了,使得我们“不知庐山真面目”;

其实就是定义了一个“syncedName”的Computed,它的get访问器返回“this.name”,然后set访问器去通知父组件更新这个name

@Emit

这是最难理解的一个装饰器了,因为它里面有很多“潜规则”

子组件与父组件通信的方法:this.$emit(EventName,...args)

@Emit的写法

@Emit('add')
addOne(n){
    this.count += n
    return n+this.count
}

先把结论抛出来:

  1. Emit函数的参数是事件名称
  2. methods的参数是$emit传递的数据;但是如果遇到返回值会放在返回值后面
  3. 函数的返回值作为$emit传递的数据中第一个参数
  4. 函数返回一个promise,那么会把promise resolve之后的值作为传递的数据

再来思考我们上面写的代码,你能够一口气把它转化为我们平时写的vue代码吗?

addOne(n){
    this.count+=n
    this.$emit('add',n+this.count,n)
}

是不是足够复杂??但是如果记住上面的铁律,那么一切都解决了

@VModel

有这样一个需求:需要v-model绑定一个父组件传递过来的参数,该怎么办呢?

我们需要借助Computed来实现,在get访问器中返回这个props,然后在set访问器将新的值传递给父组件

 @Prop() private readonly value;
  public get inputValue(): void {
    return this.value
  }
  public set inputValue(val) {
    this.$emit('input',val)
  }

@Ref

我们在操作Dom的时候经常需要使用到ref;但是如果每次都使用“this.$refs.xxx”显然不太方便,我们可以使用@Ref,它像等于将这个dom节点存储到Computed中

这样使用还有一个好处可以标注dom元素的类型,使用的时候有智能提示,非常友好,不用每次as any了!

@Ref('myButton') readonly button!:HTMLButtonElement;

// 等同于
get button(){
    return this.$refs.myButton as HTMLButtonElement
}

总结:今天我们梳理了一下vue-property-decorator的用法,简化了我们的类组件;后续我们讲解一下vuex的类的写法,欢迎阅读