vue-property-decorator的使用解读

 更新时间:2025年06月11日 11:31:41   作者:&活在当下&  
这篇文章主要介绍了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>

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • electron-vue 运行报错 Object.fromEntries is not a function的解决方案

    electron-vue 运行报错 Object.fromEntries is not a function

    Object.fromEntries() 是 ECMAScript 2019 新增的一个静态方法,用于将键值对列表(如数组)转换为对象,如果在当前环境中不支持该方法,可以使用 polyfill 来提供类似功能,接下来通过本文介绍electron-vue 运行报错 Object.fromEntries is not a function的解决方案
    2023-05-05
  • Vue-Router路由守卫详的细用法教程

    Vue-Router路由守卫详的细用法教程

    在Vue.js应用中,Vue-Router是一个非常重要的插件,它允许我们实现页面间的导航,然而,仅仅实现导航是不够的,我们还需要在导航的不同阶段进行各种操作,本文将结合实际案例,详细介绍Vue-Router路由守卫的用法,需要的朋友可以参考下
    2024-12-12
  • 解决vue 表格table列求和的问题

    解决vue 表格table列求和的问题

    今天小编就为大家分享一篇解决vue 表格table列求和的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-11-11
  • Vue的Flux框架之Vuex状态管理器

    Vue的Flux框架之Vuex状态管理器

    本文内容主要参考官方教程,为了方便理解,用更加通俗的文字讲解Vuex,也原文内容做一些重点引用。希望会对你有所帮助。
    2017-07-07
  • vue使用swiper的时候第二轮事件不会触发问题

    vue使用swiper的时候第二轮事件不会触发问题

    这篇文章主要介绍了vue使用swiper的时候第二轮事件不会触发问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • 你点的 ES6一些小技巧,请查收

    你点的 ES6一些小技巧,请查收

    本文给大家总结ES6新特性:默认参数、reduce、解构赋值和Set在使用时的一些小技巧。需要的朋友参考下吧
    2018-04-04
  • 基于WebRTC实现音视频通话功能

    基于WebRTC实现音视频通话功能

    WebRTC作为一种开放标准的实时通信协议,能轻松实现浏览器之间的实时音视频通信,本次主要分享基于WebRTC的音视频通话技术,讲解WebRTC原理和音视频传输等关键概念,通过案例实践,带大家掌握如何搭建一个音视频通话应用,需要的朋友可以参考下
    2024-05-05
  • ElementUI实现在下拉列表里面进行搜索功能详解

    ElementUI实现在下拉列表里面进行搜索功能详解

    有时候需要用到下拉列表全选和搜索,下面这篇文章主要给大家介绍了关于ElementUI实现在下拉列表里面进行搜索功能的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-04-04
  • Vue子组件内的props对象参数配置方法

    Vue子组件内的props对象参数配置方法

    这篇文章主要介绍了 Vue 子组件内的  props 对象里的 default 参数是如何定义Array、 Object 、或 Function 默认值的正确写法说明,感兴趣的朋友跟随小编一起看看吧
    2022-08-08
  • 详解vue如何封装封装一个上传多张图片的组件

    详解vue如何封装封装一个上传多张图片的组件

    上传图片不管是后台还是前端小程序,上传图片都是一个比不可少的功能有时候需要好几个页面都要上传图片,每个页面都写一个非常不方便,本文就给大家介绍vue如何封装一个上传多张图片的组件,需要的朋友可以参考下
    2023-07-07

最新评论