Vue Property Decorator

Install

The vue-property-decorator library is needed

npm i -S vue-property-decorator
Copy the code

Usage

There are several modifications to it and 1 function(Mixin):

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

See also

vuex-class

@Prop(options: (PropOptions | Constructor[] | Constructor) = {}) decorator

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

@Component
export default class YourComponent extends Vue {
  @Prop(Number) readonly propA: number | undefined
  @Prop({ default: 'default value'}) readonly propB! :string
  @Prop([String.Boolean]) readonly propC: string | boolean | undefined
}
Copy the code

Is equivalent to

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

Remind:

If you’d like to set type property of each prop value from its type definition, you can use reflect-metadata.

  1. Set emitDecoratorMetadata to true.
  2. Import reflect-metadata before importing vue-property-decorator (importing reflect-metadata is needed just once.)
import 'reflect-metadata'
import { Vue, Component, Prop } from 'vue-property-decorator'

@Component
export default class MyComponent extends Vue {
  @Prop() age! :number
}
Copy the code

Each prop’s default value need to be defined as same as the example code shown in above.

It’s not supported to define each default property like @Prop() prop = 'default value' .

@PropSync(propName: string, options: (PropOptions | Constructor[] | Constructor) = {}) decorator

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

@Component
export default class YourComponent extends Vue {
  @PropSync('name', { type: String}) syncedName! :string
}
Copy the code

Is equivalent to

export default {
  props: {
    name: {
      type: String}},computed: {
    syncedName: {
      get() {
        return this.name
      },
      set(value) {
        this.$emit('update:name', value)
      }
    }
  }
}
Copy the code

Other than that it works just like @Prop other than it takes the propName as an argument of the decorator, in addition to it creates a computed getter and setter behind the scenes. This way you can interface with the property as it was a regular data property whilst making it as easy as appending the .sync modifier in the parent component.

@Model(event? : string, options: (PropOptions | Constructor[] | Constructor) = {}) decorator

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

@Component
export default class YourComponent extends Vue {
  @Model('change', { type: Boolean}) readonly checked! :boolean
}
Copy the code

Is equivalent to

export default {
  model: {
    prop: 'checked'.event: 'change'
  },
  props: {
    checked: {
      type: Boolean}}}Copy the code

@Model property can also set type property from its type definition via reflect-metadata .

@Watch(path: string, options: WatchOptions = {}) decorator

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

@Component
export default class YourComponent extends Vue {
  @Watch('child')
  onChildChanged(val: string, oldVal: string) {}

  @Watch('person', { immediate: true, deep: true })
  onPersonChanged1(val: Person, oldVal: Person) {}

  @Watch('person')
  onPersonChanged2(val: Person, oldVal: Person) {}
}
Copy the code

Is equivalent to

export default {
  watch: {
    child: [{handler: 'onChildChanged'.immediate: false.deep: false}].person: [{handler: 'onPersonChanged1'.immediate: true.deep: true
      },
      {
        handler: 'onPersonChanged2'.immediate: false.deep: false}},methods: {
    onChildChanged(val, oldVal) {},
    onPersonChanged1(val, oldVal) {},
    onPersonChanged2(val, oldVal) {}
  }
}
Copy the code

@Provide(key? : string | symbol) / @Inject(options? : { from? : InjectKey, default? : any } | InjectKey) decorator

import { Component, Inject, Provide, Vue } from 'vue-property-decorator'

const symbol = Symbol('baz')

@Component
export class MyComponent extends Vue {
  @Inject() readonly foo! :string
  @Inject('bar') readonly bar! :string
  @Inject({ from: 'optional'.default: 'default'}) readonly optional! :string
  @Inject(symbol) readonly baz! :string

  @Provide() foo = 'foo'
  @Provide('bar') baz = 'bar'
}
Copy the code

Is equivalent to

const symbol = Symbol('baz')

export const MyComponent = Vue.extend({
  inject: {
    foo: 'foo'.bar: 'bar'.optional: { from: 'optional'.default: 'default' },
    [symbol]: symbol
  },
  data() {
    return {
      foo: 'foo'.baz: 'bar'
    }
  },
  provide() {
    return {
      foo: this.foo,
      bar: this.baz
    }
  }
})
Copy the code

@ProvideReactive(key? : string | symbol) / @InjectReactive(options? : { from? : InjectKey, default? : any } | InjectKey) decorator

These decorators are reactive version of @Provide and @Inject. If a provided value is modified by parent component, then the child component can catch this modification.

const key = Symbol()
@Component
class ParentComponent extends Vue {
  @ProvideReactive() one = 'value'
  @ProvideReactive(key) two = 'value'
}

@Component
class ChildComponent extends Vue {
  @InjectReactive() one! :string
  @InjectReactive(key) two! :string
}
Copy the code

@Emit(event? : string) decorator

The functions decorated by @Emit $emit their return value followed by their original arguments. If the return value is a promise, it is resolved before being emitted.

If the name of the event is not supplied via the event argument, the function name is used instead. In that case, the camelCase name will be converted to kebab-case.

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

@Component
export default class YourComponent extends Vue {
  count = 0

  @Emit()
  addToCount(n: number) {
    this.count += n
  }

  @Emit('reset')
  resetCount() {
    this.count = 0
  }

  @Emit()
  returnValue() {
    return 10
  }

  @Emit()
  onInputChange(e) {
    return e.target.value
  }

  @Emit()
  promise() {
    return new Promise(resolve= > {
      setTimeout((a)= > {
        resolve(20)},0)}}}Copy the code

Is equivalent to

export default {
  data() {
    return {
      count: 0}},methods: {
    addToCount(n) {
      this.count += n
      this.$emit('add-to-count', n)
    },
    resetCount() {
      this.count = 0
      this.$emit('reset')
    },
    returnValue() {
      this.$emit('return-value'.10)
    },
    onInputChange(e) {
      this.$emit('on-input-change', e.target.value, e)
    },
    promise() {
      const promise = new Promise(resolve= > {
        setTimeout((a)= > {
          resolve(20)},0)
      })

      promise.then(value= > {
        this.$emit('promise', value)
      })
    }
  }
}
Copy the code

@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 }Copy the code

Is equivalent to

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

Concerned about my public number irregularly share front-end knowledge, progress with you!