vue 中使用 TS 的 class-style代码风格

前言:

vue 中使用 typescript的 class-style 风格代码,除了用到ts的语法,还用到了 vue-property-decorator语法 vue-class-component语法

vue-property-decorator 与 vue-class-component 的关系

vue class component 是vue 官方出的
vue property decorator 是社区出的
其中vue class component 提供了 vue component 等等
vue property decorator 深度依赖了 vue class component 拓展出了很多操作符 @Prop @Emit @Inject 等等 可以说是 vue class component 的一个超集
正常开发的时候 你只需要使用 vue property decorator 中提供的操作符即可 不用再从vue class componen 引入vue component

一、如何使用(官网介绍

1、导入npm 包

npm i -S vue-property-decorator

主要有以下一些装饰器和一个方法

@Prop
@PropSync
@Model
@ModelSync
@Watch
@Provide
@Inject
@ProvideReactive
@InjectReactive
@Emit
@Ref
@VModel
@Component (provided by vue-class-component)
Mixins (the helper function named mixins provided by vue-class-component)

@Component

注: 该属性完全继承于vue-class-component
属性参数:@Component(options: ComponentOptions = {})
参数说明:@Component 装饰器可以接收一个对象作为参数,可以在对象中声明 components ,filters,directives, beforeRouteLeave等未提供装饰器的选项,也可以声明computed,watch等

<template>
    <div class="parent">
        parent组件--{{title}}
        <hr>
        <Home v-model="title"></Home>
        <About v-model="title"></About>
    </div>
</template>

1、js 写法

<script>
import Home from './Home.vue'
import About from './About.vue'
export default {
    data() {
        return {
            title: '父组件中的值'
        }
    },
    components: {
        Home,
        About
    }
}
</script>

2、ts 写法

<script lang='ts'>
    import Home from './Home.vue'
    import About from './About.vue'
    import { Component, Vue } from 'vue-property-decorator';
    @Component({
        components: {
            Home,
            About
        }
    })
    export default class  extends Vue {
        private title: string = '父组件中的值'
    }
</script>

@Emit

属性参数:@Emit(event?: string)
参数说明:
@Emit 装饰器接收一个可选参数,充当事件名。如果没有提供这个参数,@Emit会将回调函数名的camelCase转为kebab-case,并将其作为事件名;
@Emit的回调函数的参数,会在回调函数没有返回值的情况下,被$emit当做第二个参数使用。
@Emit会将回调函数的返回值作为第二个参数,如果返回值是一个Promise对象,$emit会在Promise对象被标记为resolved之后触发;

<template>
  <div class="home">
    vue+ts项目vue-property-decorator用法
    <hr>
    <button @click="triggerEmit('qqq')">触发emit</button>
  </div>
</template>

1、js写法

export default {
  data() {
    return {}
  },
  mounted() {
    this.$on('trigger-emit', data => {
      alert(data)
    })
  },
  methods: {
    triggerEmit(val) {
      this.$emit('trigger-emit', val)
    }
  }
}

2、ts写法

<script lang="ts">
import { Component, Vue, Emit } from 'vue-property-decorator';

@Component({})
export default class Home extends Vue {

  private mounted() {
    this.$on('demo-log', (data: any): void => {
      alert(data)
    })
  }

  @Emit('demo-log')
  triggerEmit(n: any) {
    console.log('hhh')
  }
}
</script>

另一种写法,$on位置使用 - 链接,@Emit位置直接使用驼峰命名,则可以省略括号中的名称:”

export default class Home extends Vue {
  private mounted() {
    this.$on('trigger-emit', (data: any): void => {
      alert(data)
    })
  }
  @Emit()
  triggerEmit(n: any) {
    console.log('hhh')
  }
}

案例二、
ts

<script lang="ts">
    import {Vue, Component, Emit} from 'vue-property-decorator';

    @Component
    export default class "组件名" extends Vue{
        mounted(){
            this.$on('emit-todo', function(n) {
                console.log(n)
            })

            this.emitTodo('world');
        }

        @Emit()
        emitTodo(n: string){
            console.log('hello');
        }
    }
</script>

以上代码会输出 hello world,js写法如下

<script>
    import Vue from 'vue';

    export default {
        mounted(){
            this.$on('emit-todo', function(n) {
                console.log(n)
            })

            this.emitTodo('world');
        },
        methods: {
            emitTodo(n){
                console.log('hello');
                this.$emit('emit-todo', n);
            }
        }
    }
</script>

在@Emit装饰器的函数会在运行之后触发等同于其函数名(驼峰式会转为横杠式写法)的事件, 并将其参数传递给$emit.
如果我们想触发特定的事件呢,比如在emitTodo下触发reset事件:

<script lang="ts">
    import {Vue, Component, Emit} from 'vue-property-decorator';

    @Component
    export default class "组件名" extends Vue{

        @Emit('reset')
        emitTodo(n: string){

        }
    }
</script>

我们只需要给装饰器@Emit传递一个事件名参数reset,这样函数emitTodo运行之后就会触发reset事件.

@Prop

属性参数:@Prop(options: (PropOptions | Constructor[] | Constructor) = {})
参数说明:@Prop装饰器接收一个参数,这个参数可以有三种写法:
PropOptions,可以使用以下选项:type,default,required,validator;
Constructor[],指定 prop 的可选类型;
Constructor,例如String,Number,Boolean等,指定 prop 的类型;

注意:

属性的ts类型后面需要加上undefined类型;或者在属性名后面加上!,表示非null 和 非undefined的断言,告诉TypeScript我这里一定有值,否则编译器会给出错误提示;
!: 表示一定存在,?: 表示可能不存在。这两种在语法上叫赋值断言
比如子组件从父组件接收三个属性propA,propB,propC
propA类型为Number
propB默认值为default value
propC类型为String或者Boolean

export default {
  props: {
    propA: {
      type: Number
    },
    propB: {
      default: 'default value'
    },
    propC: {
      type: [String, Boolean]
    },
  }
}

使用vue-property-decorator提供的@Prop可以将上面的代码改造为如下:

<script lang="ts">
    import {Vue, Component, Prop} from 'vue-property-decorator';

    @Component
    export default class "组件名" extends Vue{
        @Prop(Number) propA!: number;
        @Prop({default: 'default value'}) propB!: string;
        @prop([String, Boolean]) propC: string | boolean;
    }
</script>

@Prop接受一个参数可以是类型变量或者对象或者数组.@Prop接受的类型比如Number是JavaScript的类型,之后定义的属性类型则是TypeScript的类型.

@Ref

属性参数:@Ref(refKey?: string)
参数说明:@Ref 装饰器接收一个可选参数,用来指向元素或子组件的引用信息。如果没有提供这个参数,会使用装饰器后面的属性名充当参数

posted @ 2021-04-24 11:52  清和时光  阅读(5733)  评论(0编辑  收藏  举报