vue-property-decorator

    |     2020年4月23日   |   vuejs, web前端技术   |     0 条评论   |    1272

vue-property-decorator 完全依赖 vue-class-component。在 Vue 单文件里用 TypeScript 时,它把 Options API 收成装饰器:类字段当 data、get 当 computed,@Emit / @Watch / @Prop / @Model 对应事件、侦听、属性和 v-model。

它提供这些能力:

  • @Component(完全继承于 vue-class-component)
  • @Emit
  • @Inject
  • @Provide(原文写作 @Provice)
  • @Prop
  • @Watch
  • @Model
  • Mixins(在 vue-class-component 中定义)
装饰器 对应 Options API
类字段 data
get xxx() computed
@Emit / @Emit(‘name’) $emit,默认事件名是函数名(驼峰转横杠)
@Watch(‘key’, opts) watch
@Prop(type|object|array) props
@Model(event, propOptions) model + 对应 prop

一、基本用法:data 与 computed

引入之后,script 可以写成:

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

    @Component({})
    export default class "组件名" extends Vue{
        ValA: string = "hello world";
        ValB: number = 1;
    }
</script>

等同于

<script lang="es6">
    import Vue from 'vue';

    export default {
        data(){
            return {
                ValA: 'hello world',
                ValB: 1
            }
        }
    }
</script>
  • 总结:data 里的变量,按 TS 类字段来写即可。

计算属性用 getter:

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

    @Component({})
    export default class "组件名" extends Vue{
        get ValA(){
            return 1;
        }
    }
</script>

等同于

<script lang="es6">
    import Vue from 'vue';

    export default {
        computed: {
            ValA: function() {
                return 1;
            }
        }
    }
</script>
  • 总结:把计算属性名写成函数,前面加 get。原来 computed 里每一项都变成前缀 get 的函数。

二、@Emit

Vue 用 $emit / $on 做事件。装饰器版用 @Emit:

<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’。等同于:

<script lang="es6">
    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>

给装饰器传事件名即可。函数参数会在触发时传出去。两种写法:

  1. @Emit() 不传参,事件名就是函数名。
  2. @Emit(name: string) 传入要触发的事件名。

三、@Watch

用 @Watch 替换 Options 里的 watch。Vue 里常见写法:

export default{
    watch: {
        'child': this.onChangeValue
            // 这种写法默认 `immediate`和`deep`为`false`
        ,
        'person': {
            handler: 'onChangeValue',
            immediate: true,
            deep: true
        }
    },
    methods: {
        onChangeValue(newVal, oldVal){
            // todo...
        }
    }
}

装饰器版:

import {Vue, Component, Watch} from 'vue-property-decorator';

@Watch('child')
onChangeValue(newVal: string, oldVal: string){
    // todo...
}

@Watch('person', {immediate: true, deep: true})
onChangeValue(newVal: Person, oldVal: Person){
    // todo...
}
  • 第一个参数是要监听的属性名,第二个是可选对象。被装饰的函数就是变化后的处理。

四、@Prop

子组件收父组件参数时要定义 Prop。例如三个属性:

  • propA 类型 Number
  • propB 默认 ‘default value’
  • propC 类型 String 或 Boolean
export default {
  props: {
    propA: {
      type: Number
    },
    propB: {
      default: 'default value'
    },
    propC: {
      type: [String, Boolean]
    },
  }
}

改成:

<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>

这里 ! 和可选参数 ? 相反,告诉 TypeScript 这里一定有值。

  • @Prop 参数可以是类型、对象或数组。里面的 Number 是 JavaScript 类型,后面属性类型才是 TypeScript 类型。

五、Mixins

结合 TypeScript 后有两种 mixins。第一种来自 vue-class-component:

//定义要混合的类 mixins.ts
import Vue from 'vue';
import  Component  from 'vue-class-component';

@Component  // 一定要用Component修饰
export default class myMixins extends Vue {
    value: string = "Hello"
}
// 引入
import  Component  {mixins}  from 'vue-class-component';
import myMixins from 'mixins.ts';

@Component
export class myComponent extends mixins(myMixins) {
                          // 直接extends myMinxins 也可以正常运行
      created(){
          console.log(this.value) // => Hello
    }
}

第二种:在 @Component 里混入。先改 mixins.ts,声明 vue/types/vue 模块、实现 Vue 接口:

// mixins.ts
import { Vue, Component } from 'vue-property-decorator';


declare module 'vue/types/vue' {
    interface Vue {
        value: string;
    }
}

@Component
export default class myMixins extends Vue {
    value: string = 'Hello'
}

混入:

import { Vue, Component, Prop } from 'vue-property-decorator';
import myMixins from '@static/js/mixins';

@Component({
    mixins: [myMixins]
})
export default class myComponent extends Vue{
    created(){
        console.log(this.value) // => Hello
    }
}
  • 没声明 vue/types/vue 模块时,混入要 继承 该 mixin;声明了就可以在 @Component 的 mixins 里直接混入。

六、@Model

组件的 model: {prop?: string, event?: string} 用来定制 prop 和 event。默认 v-model 用 value 作 prop、input 作 event。单选框、复选框可能要把 value 派别的用场,用 model 避开冲突。

Vue 官网例子:

Vue.component('my-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    // this allows using the `value` prop for a different purpose
    value: String,
    // use `checked` as the prop which take the place of `value`
    checked: {
      type: Number,
      default: 0
    }
  },
  // ...
})
<my-checkbox v-model="foo" value="some value"></my-checkbox>

相当于:

<my-checkbox
  :checked="foo"
  @change="val => { foo = val }"
  value="some value">
</my-checkbox>

即 foo 双向绑定的是组件的 checked,触发更新的事件是 change。装饰器版:

import { Vue, Component, Model} from 'vue-property-decorator';

@Component
export class myCheck extends Vue{
   @Model ('change', {type: Boolean})  checked!: boolean;
}
  • @Model() 两个参数:第一个是 event,第二个是 prop 的类型说明(类似 @Prop,用 JS 类型)。后面再写 prop 名和 TS 类型。

暂时常用的就这些,@Provide 和 @Inject 用到了再写。

参考: https://juejin.im/post/5d31907a51882557af271be2#heading-0

链接:https://www.jianshu.com/p/d8ed3aa76e9b

一句话总结:vue-property-decorator 就是用装饰器把 Vue 选项写成 TS 类:字段是 data,get 是 computed,Emit / Watch / Prop / Model / Mixins 一一对应原来的配置项。

转载请注明来源:vue-property-decorator
本文链接地址:https://ai.zhousir.top/?p=2912
回复 取消