vue-property-decorator装饰器用法

LeslieLin 编程技术
阅读量 0 评论量 0

前言

在Vue中使用typescript,通过使用vue-property-decorator装饰器来简化书写。

装饰器

  • @Component
  • @Emit
  • @Prop
  • @PropSync
  • @Watch
  • @Inject
  • @Provide
  • @Model
  • @Ref
  • Mixins

@Component 声明组件

import { Vue,Component } from 'vue-property-decorator'
import {componentA} from '@/components'
@Component({
    components: {componentA} // 其他组件声明
})
// @Component
export default class '组件名' extends Vue {
    private valueA: string = '我是ValueA'  // data里的变量
    private valueB: number[] = [1,2,3]
    private get valueC () {  // 计算属性,相当于getter
        return 1
    }
    public render() {
        return (<div>...</div>)
    }
}

等同于

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

    export default {
        data(){
            return {
                ValA: '我是ValueA',
                ValB: [1,2,3]
            }
        },
      computed: {
        valueC: function() {
          return 1;
        }
      }
    }
</script>

总结: 对于data里的变量,直接按ts定义类变量的写法写即可

@Emit 事件触发

  // 子组件
  @Emit() // 参数为父组件绑定事件名,不写默认跟随的函数名称[这种情况下,camelCase名称将转换为kebab-case]
  private emitChange() {
     return 'something' // 如果想返回值,可以这边return 
  }

  @Emit('reset') 
  private emitChange1() {
     return 'something' // 如果想返回值,可以这边return
  }

  // 父组件
  <child onReset={(res: any) => this.parentHandleChange(res)}>
<script lang="ts">
    import {Vue, Component, Emit} from 'vue-property-decorator';

    @Component({})
    export default class '组件名' extends Vue{
        mounted(){
            this.$on('emit-todo', function(what) {
                console.log(waht)
            })
            this.emitTodo('接收');
        }

        @Emit()
        emitTodo(what: string){
            console.log('发送emitTodo');
        }
    }
</script>

等同于

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

    export default {
        mounted(){
            this.$on('emit-todo', function(what) {
                console.log(what)
            })
            this.emitTodo('接收');
        },
        methods: {
            emitTodo(what){
                console.log('发送emitTodo');
                this.$emit('emit-todo', what);
            }
        }
    }
</script>
  1. @Emit不传参,那么它触发的事件名就是他所修饰的函数名
  2. @Emit(name: string)里面传递一个字符串,该字符串为要触发的事件名

@Watch 值监听变化

watch方法需要声明在变量和jsx之后

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

@Watch的用法

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...
}
  • @Watch接受第一个参数为要监听的属性名 第二个属性为可选对象.@Watch所装饰的函数即监听到属性变化之后的操作.

@Prop

<script>
// javascript的vue写法
export default {
  props: {
    propA: {
      type: Number
    },
    propB: {
      default: 'default value'
    },
    propC: {
      type: [String, Boolean]
    },
  }
}
</script>

ts改造如下

<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;
        @propC([String, Boolean]) propC: string | boolean;
    }
</script>

!代表必填参数,?代表可选参数

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

mixins

  // mixins.ts
  export default class MyMixins extends Vue{
    value: string ='hi'
  }
  // 引入
  // 方法一  vue-class-component提供
  import {mixins} from 'vue-class-component'
  import myMixins from 'mixin.ts'
@Componnet
  export default class myCom extends mixins(myMixins){
      public create () {
        console.log(this.value)
      }
  }

  // 方法二 @Component中混入
  // mixins.ts
  declare module 'vue/types/vue' {
      interface Vue {
        value: string
    }
  }
  @Component
  export default class myMixins extends Vue {
    value: string = 'hello'
  }
 // 引入
  @Component({
    mixins: [myMixins]
  })
export default class myCom extends mixins(myMixins){
     public create () {
        console.log(this.value)
      }
  }
  • 两种方式不同的是在定义mixins时如果没有定义vue/type/vue模块, 那么在混入的时候就要继承mixins; 如果定义vue/type/vue模块,在混入时可以在@Componentmixins直接混入.

@Model

Vue组件提供model: {prop?: string, event?: string}让我们可以定制propevent.
默认情况下,一个组件上的v-model. 会把value.用作prop且把input用作event,但是一些输入类型比如单选框和复选框按钮可能想使用value prop来达到不同的目的。使用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

使用vue-property-decor提供的@Model改造上面的例子.

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

@Component
export class myCheck extends Vue{
   @Model ('change', {type: Boolean})  checked!: boolean;
}
  • @Model()接收两个参数, 第一个是event值, 第二个是prop的类型说明, 与@Prop类似.

@Provide提供/@Inject注入

父组件不便于向子组件传递数据,就把数据通过provide传递下去,然后子组件通过Inject来获取

 // js写法
  data() {return {foo: 'foo'}}
  provide() {
    return { foo, this.foo}
  }
  inject: {
    
  }

// ts
import {Vue,Component,Inject,Provide} from 'vue-property-decorator'
@Component
export defalut class MyComponent extends Vue{ 
  @Inject()
  foo!: string
  @Inject('bar')
  bar!: string
  @Inject({ from:'optional', default:'default'})
  optional!: string;

  @Provide()
  foo = 'foo'
    
  @Provide('bar')
  baz = 'bar'
}

@Ref

(refKey?: string) decorator

import { Vue, Component, Ref } from 'vue-property-decorator'
import AnotherComponent from '@/path/to/another-component.vue'
 
@Component
export default class YourComponent extends Vue {
  @Ref() readonly anotherComponent!: AnotherComponent
  @Ref('aButton') readonly button!: HTMLButtonElement
}

等同于

export default {
  computed() {
    anotherComponent: {
      cache: false,
      get() {
        return this.$refs.anotherComponent as AnotherComponent
      }
    },
    button: {
      cache: false,
      get() {
        return this.$refs.aButton as HTMLButtonElement
      }
    }
  }
}

@PropSync暂时没有用到。

喵~