vue-property-decorator

by kaorun343

Vue.js and Property Decorator

4.1K Stars 277 Forks Last release: 5 months ago (v8.4.2) MIT License 285 Commits 35 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

Vue Property Decorator

npm Build Status

This library fully depends on vue-class-component, so please read its README before using this library.

License

MIT License

Install

npm i -S vue-property-decorator

Usage

There are several decorators and 1 function (Mixin):

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 }

is equivalent to

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

Note that:

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 }

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 }

is equivalent to

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

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

is equivalent to

export default {
  model: {
    prop: 'checked',
    event: 'change',
  },
  props: {
    checked: {
      type: Boolean,
    },
  },
}

@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) {} }

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) {},
  },
}

@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' }

is equivalent to

const symbol = Symbol('baz')

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

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

@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(() => { resolve(20) }, 0) }) } }

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(() => {
          resolve(20)
        }, 0)
      })

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

}, }

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

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

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.