我报名参加金石计划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
的核心文件中,可以看到可引入的装饰器如下,可以满足各种业务场景:
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()
代码如下:
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…