用了半个月装饰器语法,真香!

5,064 阅读3分钟

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情

随着前端技术不断地迭代,项目中也从 vue2 选项式 API的写法,到 Vue3 中使用setup(),再到 setup 语法糖一路升级。

后来的某一天,在一个项目中需要把代码改造成装饰器语法,在这个过程中经历了对原有代码结构认知的重塑......最后发现装饰器语法真的香!

装饰器 (Decorator)

先来说说装饰器语法好用在哪里:

  • 可以对类、对象、方法、属性进行修饰(使用类语法)
  • 可以实现逻辑的封装,减少不必要的重复
  • 代码变得更简洁,增加代码的可读性

安装及引入:

安装:

npm i -S vue-property-decorator

安装成功在页面中按需引入:

import { Watch, Prop, Emit, Mutation } from 'vue-property-decorator'

使用

1. 装饰器种类

vue-property-decorator的核心文件中,可以看到可引入的装饰器如下,可以满足各种业务场景:

image.png

2. 页面结构

相比较来说,装饰器语法的代码结构非常清晰。其中,@Options在最外面用来修饰组件。

以一个登录功能为例,装饰器语法应该是这样的:

<template>
  <div>
    <input v-model="name" /><br />
    <input v-model="pwd" /><br />
    <button @click="login">登录</button>
  </div>
</template>

<script lang="ts">
import { Options, Vue } from 'vue-class-component';
import { Watch } from 'vue-property-decorator';

@Options({})
export default class Login extends Vue {
  private name = '';
  private pwd = '';

  public created(): void {
    console.log('created');
  }

  @Watch('name')
  public setName(name: string): void {
    console.log('watch: name')
  }

  public get user(): string {
    console.log(this.name + '-' + this.pwd);
  }

  public login() {
    console.log('login',this.user);
  }
}
</script>

3. 响应式数据

曾经我们声明一个数据是这样的:

data: {
    msg:'hahaha'
}

或者在setup中是这样的:

<script setup lang="ts">
    let msg = ref('hahaha');
    const data = reactive({
        name:'',
        age:''
    })

    const { name, age } = toRefs(data)
<script>

在装饰器语法中:

直接声明变量就是响应式的

public msg = 'hahaha'

4. 生命周期函数的使用

在vue的核心文件中,ClassComponentHooks的定义可以看到是没有 setup 的,所以装饰语法中,直接声明created()或是mounted()

image.png

代码如下:

public created(): void {
    // TODO
}
public mounted(): void {
    // TODO
}

5. 引入组件

在页面中使用其它组件时,需要在@Options中配置components属性

import { MyComp } from '@/components/myComp';
@Options({components: { MyComp }})

6. 父子组件交互

@Prop@Emit 可以帮助我们实现父子组件数据的交互.如果有多个数据传入,就要写多个@Prop

父传子:

@Prop({ default: '' }) readonly msg: string | undefined

子传父:

@Emit() 
changeVal(msg: string) { 
    return msg 
}
public sendMsg(): void {
    this.changeVal()
}

@Emit装饰的函数名称即为事件名称:

// 父组件
<div @change-val=""></div>

7.监听和计算

计算:

get sum(){ return this.a + this.b; }

监听:

当监听的数据是对象或是数组对象,可以设置deep属性,立即执行则设置immediate:true

@Watch('msg',{deep:false})
onChangeVal(val: string, oldVal: string){
    // TODO
}

8. Ref 获取组件实例

使用Ref分为三步:引入组件,声明@Ref,调用。

import { Options, Vue } from 'vue-class-component';
import { Ref } from 'vue-property-decorator'
import { MyComp } from '@/components/myComp';

@Options({components: { MyComp }})
export default class Input extends Vue {
    @Ref() readonly myCompRef = MyComp
    
    public clickFunc = () => {
        this.myCompRef.open() // open() 为 MyComp 组件中定义的方法
    }
}

上面的形式相当于:

computed() {
    myCompRef: {
        cache: false,
        get() {
            return this.$refs.myCompRef as MyComp
        }
    }
}

上述的装饰器语法只是其中的一部分,还有一些如 @Provide@Inject@Model等语法可以参考:github.com/kaorun343/v…