vue-property-decorator 用法详解

最近接触了一个新项目,是基于 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>
### 回答1: vue-property-decorator 是一个用于简化 Vue.js 组件开发的装饰器库,而 Vue 3 是 Vue.js 的下一个主要版本。vue-property-decorator 目前仅适用于 Vue 2.x 版本,并在 Vue 3.x 中不再兼容。 Vue 3 意味着对 Vue.js 进行了大规模重写和重构,旨在提供更高性能、更小的包大小、更好的开发体验和更多功能。Vue 3 引入了许多新特性,例如 Composition API、Teleport、Suspense 等。 由于 Vue 3 中改编了大量的底层代码,vue-property-decoratorVue 3.x 中不再适用,这是因为 Vue 3 在其组件定义和交互方式上引入了一些改变。为了使现有的代码能够在 Vue 3.x 中运行,我们需要采用其他方式来替代 vue-property-decorator,用于装饰 Vue 组件的功能。 Vue 3 中提供了一种新的组合式 API - Composition API,它允许我们使用函数的形式组织和复用逻辑。通过 Composition API,我们可以在 Vue 组件中按照逻辑功能划分代码,使得组件更加清晰和可维护。虽然和 vue-property-decorator 的装饰器方式不同,但 Composition API 提供了一种更灵活和直观的方式来开发 Vue 组件。 总结来说,vue-property-decorator 是用于 Vue 2.x 版本的装饰器库,而 Vue 3.x 引入了新的 Composition API,取代了 vue-property-decorator,提供了更好的开发体验和更多的功能。所以在 Vue 3.x 中使用 vue-property-decorator 是不可行的,我们需要使用 Composition API 来替代。 ### 回答2: vue-property-decorator是一个用于在Vue组件中使用装饰器语法的库。它使我们能够更加简洁和优雅地编写Vue组件,同时提供了一些强大的功能和特性。 首先,vue-property-decorator允许我们使用装饰器来定义组件的属性,方法和计算属性。通过使用装饰器,我们可以将组件的相关代码集中在一起,使代码更加易读和易维护。例如,我们可以使用@Prop装饰器来定义组件的属性,并指定其类型和默认值。我们还可以使用@Watch装饰器来监听属性或计算属性的变化。 其次,vue-property-decorator提供了一些方便的装饰器来简化对组件生命周期钩子的使用。我们可以使用@Emit装饰器来触发自定义事件,使用@Provide装饰器来提供数据,使用@Inject装饰器来注入数据等。这些装饰器使我们能够更加方便地在组件之间进行通信和共享数据。 此外,vue-property-decorator还提供了一些装饰器来简化对Vue指令和插件的使用。通过使用@Directive装饰器,我们可以定义自定义指令并将其应用到组件中,而无需手动注册和使用指令。类似地,使用@Plugin装饰器,我们可以将第三方插件集成到组件中,从而增强组件的功能。 总而言之,vue-property-decorator是一个强大而灵活的库,它使我们能够更加方便地使用装饰器语法编写Vue组件。它提供了一些强大的功能和特性,使我们的代码更加简洁和易读。对于使用Vue 3的开发者来说,vue-property-decorator无疑是一个很好的选择。 ### 回答3: vue-property-decorator是一个用于Vue.js框架的装饰器库,它能够简化开发者在使用类风格的语法时对Vue组件属性的管理和操作。 在Vue.js 3版本中,vue-property-decorator已经进行了更新和迁移,与Vue.js 2版本的使用稍有区别。在Vue.js 3中,可以使用新的@Options装饰器以替代之前的@Component装饰器,同时也可以继续使用@property装饰器来声明和管理组件的属性。 @Options装饰器可以用于修饰一个Vue组件类,它接受一个配置对象作为参数,用来定义组件的选项和行为。例如: ``` import { Options, Vue } from 'vue-property-decorator'; @Options({ props: { message: { type: String, required: true } } }) export default class MyComponent extends Vue { // 组件的其他逻辑... } ``` 上述代码中,使用@Options装饰器修饰了一个Vue组件类,并通过props字段定义了一个名为message的属性,类型为String,且是必需的。 同时,我们仍然可以使用@property装饰器来声明和管理组件的其他属性。例如: ``` import { Options, Vue, property } from 'vue-property-decorator'; @Options({}) export default class MyComponent extends Vue { @property({ type: String }) message: string = ''; // 组件的其他逻辑... } ``` 上述代码中,使用@property装饰器修饰了一个名为message的属性,并指定了它的类型为String。 总的来说,vue-property-decorator能够简化Vue.js 3中使用类风格语法时对组件属性的管理和操作,提供了方便的装饰器来声明和定义组件的属性,并与Vue的选项和行为进行集成。使用它可以使代码更易读、更易维护。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值