导入
import { Vue, Options } from 'vue-property-decorator';
@Options({})
export default class extends Vue {}
计算属性
使用 get
关键字,定义为组件类的 getter 方法:
@Options({})
export default class extends Vue {
get computedValRef() {
return something;
}
}
@Emit 装饰器
emit 实现了在调用一个函数时自动执行另一个函数。
导入 @Emit 装饰器:
import { Emit } from 'vue-property-decorator';
@Emit 装饰器接受一个字符串参数,代表在执行它装饰的那个函数后需要触发执行的另一个函数。
@Emit 装饰器无参时,触发的额外函数就是其修饰的同名函数,驼峰函数名会被转化为连字符函数名。
@Emit 装饰器触发的额外函数总是在其修饰的函数执行之后执行,并将其修饰的函数的参数作为参数。
下面是一个例子:
import { Vue, Options, Emit } from 'vue-property-decorator';
@Options({})
export default class extends Vue {
mounted() {
// 使用$on挂载一个事件emit-something
this.$on('emit-something', function(s: string) {
console.log(s);
});
this.emitSomething('world');
}
// 无参的@Emit装饰器,触发同名函数emit-something
@Emit()
emitSomething(s: string) {
console.log('hello');
}
}
在上面的例子中,emit-something
是组件的一个自定义 事件,在使用这个组件时,可以通过 @emit-something="func"
来执行父组件中的 func()
事件函数,func()
函数的参数应当与子组件 emitSomething()
函数的参数一致。
下面是一个具体例子:
-
父组件:
<template> <ChildComponent @emit-message="handleEmitSomething" /> </template> <script> import { Vue, Options } from 'vue-property-decorator'; @Options({}) export default class extends Vue { handleEmitSomething(s: string) { console.log('Receive from child:', s); } } </script>
-
子组件
<template> <button @click="() => emitSomething('hello father')">Click</button> </template> <script> import { Vue, Options, Emit } from 'vue-property-decorator'; @Options({}) export default class extends Vue { @Emit('emit-message') emitSomething(s: string) { console.log('ChildComponent: run emitSomething'); } } </script>
子组件只提供了一个按钮,点击按钮执行子组件中的 emitSomething()
函数。
emitSomething()
函数被 @Emit装饰器 修饰,自动触发子组件的 emit-message 事件。
子组件的(自定义)事件需要父组件进行处理,父组件的 handleEmitSomething()
函数处理此事件。
handleEmitSomething()
函数的参数应该与子组件的 emitSomething()
函数保持一致。
emitSomething()
函数的 实参 会赋给 handleEmitSomething()
函数的 形参。
最后点击子组件的按钮,打印的结果如下:
ChildComponent: run emitSomething
Receive from child: hello father
@Model 装饰器
@Model装饰器 实现了父子组件数据的 双向绑定。
父组件中,通过指定子组件的 v-model
属性对变量进行双向绑定。
下面的例子中,父组件的 content
变量与 Child
子组件双向绑定:
<template>
<Child v-model="content"></Child>
</template>
<script>
import { Vue, Options } from 'vue-property-decorator';
@Options({})
export default class extends Vue {
content: string;
}
</script>
子组件中也需要定义一个变量,来实现双向绑定:
<template>
<input type="text" :value="str" @input="$emit('update:modelValue', $event.target.value)" />
</template>
<script>
import { Vue, Options, Model } from 'vue-property-decorator';
@Options({})
export default class extends Vue {
@Model('modelValue', String) str!: string;
}
</script>
在 Vue3 中,@Model
装饰器接受两个参数:
propName: string
:调用子组件时v-model:xxx
使用的标志xxx
,v-model
则使用默认标志modelValue
;propOptions?: Constructor | Constructor[] | PropOptions<any, any> | undefined
上面的例子中,子组件使用 @Model('modelValue', String)
修饰了 str
变量,意味着 str
变量绑定的属性名称是 v-model
,从而与父组件的 conetenr
变量实现双向绑定。
但是,@Model
装饰器只是声明了父子组件中用于双向绑定的两个变量,并没有指明触发数据同步的事件。
在 Vue3 中,子组件通过 update:xxx
事件来触发数据同步,因此上面的子组件调用等价于:
<template>
<Child :str="content" @update:modelValue="(val) => content = val"></Child>
</template>
v-model
其实是一种特殊的值传递:
- 通过
v-bind
指令将值传递给子组件 - 通过子组件上的
update:xxx
事件将子组件的值更新回父组件
所以子组件必须要对 update:xxx
事件作出定义,即使用 $emit
或者 @Emit
对 update:xxx
进行触发绑定。
在例子中子组件的定义中可以看到,update:xxx
事件被绑定到了子组件的 input 组件上。
当 input 组件的值发生变化时,触发子组件的 update:xxx
事件,并将 input 组件的值传递给 update:xxx
事件。
触发子组件的 update:xxx
事件即意味着接着执行父组件中 `@update:xxx 指定的函数,从而实现值的回传。
@Model装饰器 还可以指定其他负责回传的事件名,无论如何都需要子组件使用 emit 进行触发绑定。
评论区