vue-property-decorator 用法详解
Vue 装饰器
最近接触了一个新项目,是基于 Webpack 搭建的 Vue2+TypeScript 项目,里面用的语法有些新奇,经查阅资料,发现用的是 vue-property-decorator ,下面是整理的笔记。
装饰器是什么
1、装饰器(Decorator)是一种与类(class)相关的语法,用来注释或修改类和类方法,许多面向对象的语言都有这项功能。
2、装饰器是一种函数,写成@ + 函数名
。它可 以放在类和类方法的定义前面。
为什么要使用 vue-property-decorator
vue-class-component
是官方推出的vue对 typescript
支持的装饰器(库),可以将 Vue 中的组件用类的方式编写。vue-property-decoretor
即vue属性装饰器,这个库完全依赖于 vue-class-component 。在 vue 中使用 typescript,通过装饰器来简化书写。
如何使用 vue-property-decorator
基本用法
<template>
<div class="text">测试</div>
</template>
<script lang="ts">
import { Vue, Component } from "vue-property-decorator";
@Component
export default class Test extends Vue {
}
</script>
<style lang="less" scoped>
.text{color:red}
</style>
lang="ts": 表示脚本当前语言是TypeScript;
@Component: 表示这个类是一个 vue 组件,@Component不能省略,否则会报错;
Test: 表示组件名
export default class Login extends Vue: 表示当前组件类是继承vue的
定义变量
data中的数据由原来的data()方法改成直接在对象中定义,data内的属性直接作为实例属性书写,默认都是public公有属性,当变量标记为private时,它就不能在声明它的类的外部访问。
<template>
<div class="text">{{uName}}--{{age}}</div>
</template>
<script lang="ts">
import { Vue, Component } from "vue-property-decorator";
@Component
export default class Test extends Vue {
uName='张三'
private age=18
}
</script>
<style lang="less" scoped>
.text{color:red}
</style>
生命周期钩子函数
<template>
<div class="text">{{uName}}--{{age}}</div>
</template>
<script lang="ts">
import { Vue, Component } from "vue-property-decorator";
@Component
export default class Test extends Vue {
uName:string = '张三'
private age:number = 18
private created():void {
console.log(`Hello,${this.uName}`);
}
}
</script>
<style lang="less" scoped>
.text{
color:red
}
</style>
方法
<template>
<button @click="sum">{{count}}</button>
</template>
<script lang="ts">
import { Vue, Component } from "vue-property-decorator";
@Component
export default class Test extends Vue {
count:number=1
private sum(){
this.count++
}
}
</script>
<style lang="less" scoped>
.text{
color:red
}
</style>
@Component 类装饰器
@Component({})可以声明components、filter、directives等未提供装饰器的vue选项,也可以声明computed、watch、路由守卫函数(beforeRouteEnter、beforeRouteLeave)等。简单的说,就是框架负责为类额外添加一些成员和功能,而开发者负责通过 注解 的方式 将数据传给框架,框架收到 注解 传入的数据后,可以用在类上。
<template>
<div>
<button @click="sum">{{count}}</button>
<ComponentA/>
</div>
</template>
<script lang="ts">
import { Vue, Component } from "vue-property-decorator";
import ComponentA from '@/component/ComponentA.vue'
@Component({
watch:{
count(n){
console.log(n);
}
},
components:{
ComponentA
}
})
export default class Test extends Vue {
count:number=1
private sum(){
this.count++
}
}
</script>
<style lang="less" scoped>
.text{
color:red
}
</style>
@Prop
父子组件之间的属性传值,子组件接收父组件传参
@Prop接受一个参数可以是类型变量或者对象或者数组.@Prop接受的类型比如Number是JavaScript的类型,之后定义的属性类型则是TypeScript的类型
//父组件 Test.vue
<template>
<div>
<button @click="sum">{{count}}</button>
<ComponentA :propA="propA" :propB="propB" :propC="propC"/>
</div>
</template>
<script lang="ts">
import { Vue, Component } from "vue-property-decorator";
import ComponentA from '@/component/ComponentA.vue'
@Component({
watch:{
count(n){
console.log(n);
}
},
components:{
ComponentA
}
})
export default class Test extends Vue {
count:number=1
private propA:number=1
private propB:boolean=true
private propC:string='你好呀'
private sum(){
this.count++
}
}
</script>
<style lang="less" scoped>
.text{
color:red
}
</style>
//子组件 ComponentA.vue
<template>
<div>
<div>{{str}}</div>
<div>下面是父组件传来的值</div>
<div>{{propA}}</div>
<div>{{propB}}</div>
<div>{{propC}}</div>
</div>
</template>
<script lang="ts">
import { Vue, Component, Prop } from "vue-property-decorator";
@Component
export default class ComponentA extends Vue{
str:string='我是子组件'
@Prop(Number) propA:number|undefined
@Prop([String,Boolean]) propB!:string|boolean
@Prop({
default:'default value'
}) propC!:string
}
</script>
<!--下面是不用装饰器的写法-->
<!--<script>
export default {
props: {
propNum: {
type: Number
},
propStr: {
default: 'default value'
},
propArr: {
type: [String, Boolean]
}
},
data(){
return {
str:'我是子组件'
}
},
}
</script>-->
需要注意的是:属性的ts类型后面需要加上undefined类型;或者在属性名后面加上!,表示非null 和 非undefined 的断言,否则编译器会给出错误提示。
@PropSync()
与 Prop 的区别是子组件可以对 props 进行更改, 并同步给父组件。
子组件 ComponentA:
<template>
<div>
<p>{{count}}</p>
<button @click="innerCount += 1">increment</button>
</div>
</template>
<script lang="ts">
import { Vue, Component, PropSync } from "vue-property-decorator";
@Component
export default class ComponentA extends Vue {
@PropSync('count') private innerCount!: number // 注意@PropSync 里的参数不能与定义的实例属性同名, 因为 props 是只读的.
}
</script>
父组件:注意父组件里绑定 props 时需要加修饰符 .sync
<template>
<ComponentA :count.sync="count"/>
</template>
<script lang="ts">
import { Vue, Component } from "vue-property-decorator";
import ComponentA from '@/component/ComponentA.vue'
@Component({
components:{
ComponentA
}
})
export default class Test extends Vue {
private count: number = 1
}
</script>
@Emit
定义emit事件,参数字符串表示分发的事件名,如果没有,则使用方法名作为分发事件名,会自动转连字符写法;
@Emit会将回调函数的返回值作为第二个参数,如果返回值为一个Promise对象,emit会在Promise-resolved后触发;
//父组件 Test.vue
<template>
<div>
<ComponentA @edit-promise="editHandle" @sum="editHandle" @editHandleEmit="editHandle" @returnValue="editHandle" />
</div>
</template>
<script lang="ts">
import { Vue, Component } from "vue-property-decorator";
import ComponentA from "@/component/ComponentA.vue";
@Component({
components: {
ComponentA
},
})
export default class Test extends Vue {
editHandle(count: any) {
console.log(count,'====');
}
}
</script>
//子组件 ComponentA.vue
<template>
<div>
<button @click="editHandle(1)">Click</button>
<button @click="returnValue(2)">returnValue</button>
<button @click="sum">sum</button>
<button @click="editPromise">promise</button>
</div>
</template>
<script lang="ts">
import { Vue, Component, Emit } from "vue-property-decorator";
@Component
export default class ComponentA extends Vue {
count: number = 0;
//@Emit(name: string),里面传递一个字符串,该字符串为要触发的事件名
@Emit("editHandleEmit")
private editHandle(n:number) {
this.count+=n
}
@Emit("returnValue")
private returnValue(n:number) {
return this.count+=n
}
//@Emit()不传参数,那么它触发的事件名就是它所修饰的函数名
@Emit()
sum() {
return this.count
}
//这里@Emit()没有传参数名,editPromise 又是驼峰命名,所以,父组件用的时候要用中划线拼接形式 edit-promise
@Emit()
editPromise() {
return new Promise(resolve => {
setTimeout(() => {
resolve(20)
}, 0)
})
}
}
</script>
@Watch 观察属性装饰器
@Watch使用非常简单,接受第一个参数为要监听的属性名 第二个属性为可选对象
{immediate?: boolean, deep?: boolean}第一个表示监听开始后是否立即调用回调函数,第二个表示监听的属性变化时是否调用回调函数
<template>
<div>
<button @click="sum">sum</button>
</div>
</template>
<script lang="ts">
import { Vue, Component, Watch } from "vue-property-decorator";
@Component
export default class ComponentA extends Vue {
count: number = 0;
sum() {
this.count++
}
@Watch('count')
countChange1(newVal:number, oldVal:number){
console.log(newVal, oldVal);
}
//immediate:其值是true或false;immediate:true代表如果在 wacth 里声明了之后,就会立即先去执行里面的handler方法,如果为 false就跟我们以前的效果一样,不会在绑定的时候就执行
@Watch('count', { immediate: true })
countChange2(newVal:number, oldVal:number){
console.log(newVal, oldVal);
}
//deep:其值是true或false;确认是否深入监听。deep的意思就是深入观察,监听器会一层层的往下遍历,给对象的所有属性都加上这个监听器(受现代 JavaScript 的限制 (以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除)
@Watch('count', { deep: true })
countChange3(newVal:number, oldVal:number){
console.log(newVal, oldVal);
}
}
</script>
计算属性
对于Vue中的计算属性,我们只需要将该计算属性名定义为一个函数,,在函数前加上get关键字即可,原本Vue中的computed里的每个计算属性都变成了在前缀添加get的函数。
<template>
<div>
<button @click="sum">sum</button>
<div>{{computedMsg}}</div>
</div>
</template>
<script lang="ts">
import { Vue, Component, Watch } from "vue-property-decorator";
@Component
export default class ComponentA extends Vue {
count: number = 0;
sum() {
this.count++
}
get computedMsg(){
return this.count;
}
set computedMsg(count: number){
}
}
</script>
@Provide 和@Inject
@Provide()、@Inject()提供了父子组件、多层嵌套组件以及兄弟组件数据传递的方法。
@Provide():父组件中通过Provide传递数据;
@Inject():子组件中通过Inject获取数据;
<template>
<div>
<div>{{desc}}</div>
<ComponentA/>
</div>
</template>
<script lang="ts">
import { Vue, Component, Provide } from "vue-property-decorator";
import ComponentA from "@/component/ComponentA.vue";
@Component({
components: {
ComponentA
},
})
export default class Test extends Vue {
desc:string="我是父组件"
//父组件中通过Provide传递数据,str1、provideStr2是定义的要传递的变量
//如果@Provide()没有传参,则要传给子组件的变量就是@Provide()后面定义的变量名
@Provide() str1:string = '你好呀!';
//如果@Provide()有传参,则要传给子组件的变量就是@Provide()中传入的参数的变量名
@Provide('provideStr2') private str2:boolean = true;
}
</script>
<template>
<div>
<div>{{str}}</div>
<div>{{str1}}</div>
<div>{{str3}}</div>
</div>
</template>
<script lang="ts">
import { Vue, Component, Inject } from "vue-property-decorator";
@Component
export default class ComponentA extends Vue {
str:string="我是子组件"
//子组件中通过Inject获取数据
// str1后面加 “!”表示,str1一定有值
// @Inject()不传参表示接受的变量名和传递的变量名一样
@Inject() private str1!: string;
// 如不确定provideStr2是否一定有值,可以加上 “|undefined”,这样就不用加 “!”
// @Inject()传参表示接受的变量名和传递的变量名不一样,@Inject()后面定义的变量为接收数据的变量
@Inject('provideStr2') str3: boolean|undefined;
}
</script>
更多推荐
所有评论(0)