Introduction to dependency libraries

vue-class-component(The official documentation)

Vue is the official Vue library that supports writing Vue code as a class

  • methodsI can just say thatClass member methods
  • Calculate attributeCan be declared asClass property accessor
  • The initialization of thedataCan be declared asClass attribute
  • data,renderHave allVue lifecycle hooksCan be used as aClass member methods
  • Decorator providedComponentAnd processingMixins writingThe way ofmixins
  • All other attributes need to be placed in the decoratorComponent

vue-property-derocator(The official documentation)

Vue-class-component is a library maintained by the Vue community based on vue-class-Component. It is an extension of the previous library, adding decorators to handle properties that would otherwise be placed in component. Here are the decorators it provides

  • @Prop
  • @PropSync
  • @Provide
  • @Model
  • @Watch
  • @Inject
  • @Emit
  • @Component(fromvue-class-componentThe libraryvue-class-component)
  • Mixins method(fromvue-class-componentlibrarymixins)

vuex-class(The official documentation)

Vuex is a library of vuex decorator writing wrapped around vuE-class-Component by major Vue contributors. It provides four decorators and a namespace

  • @State
  • @Getter
  • @Mutation
  • @Action
  • namespace

Use of decorator

Js can also be used to write decorators, the same usage, but the Ts syntax part will be different; The ESLint specification can also report errors and require some configuration changes

The installation

npm i --save vue-class-component
npm i --save vuex-class
npm i --save-dev vue-property-decorator
Copy the code

Import and Use

// Import section
import Component, { mixins } from 'vue-class-component'
// If the vue-property-decorator library is used, it is recommended to use only one library import to avoid the Component reading frequently from two different libraries in the project
import { Component, Prop, Vue } from 'vue-property-decorator'

// Use part, @Component must be written
@Component
export default class HelloWorld extends Vue {}Copy the code

vue-class-componentPart of the

data,methods,Calculate attribute,Lifecycle hookPart of the
  • The original writing
export default {
  data () {
    return {
      msg: 'msg'}},methods: {
    add () {}
  },
  mounted() {}, 
  computed: {
    newmsg () {
      return 'new ' + this.msg
    }
  }
}
Copy the code
  • Data and methods can be directly defined as class attributes, computed needs to be defined as accessor attributes, and mixins methods need to be inherited instead of imported through mixins attributes
@Component
export default class HelloWorld extends Vue { msg! :Number // data
  / / as a result of Ts used strictPropertyInitialization latest version, if the variable is not used in the constructor or the assignment, all you need to add! , perform explicit assignment assertion
  add () {} // methods
  get newmsg() { // computed
    return this.msg
  }
  mounted() {} // Lifecycle hooks
}
Copy the code
mixinsMixin method implementation
  • The original writing
import mix from './mixin'
export default {
  mixins: [mix] // Import via mixins attributes
}
Copy the code
  • Decorator writing is implemented by inheriting mix from the mixins method provided by the decorator
import Component, { mixins } from 'vue-class-component'
import mix from './mixin'

@Component
export class MyComp extends mixins(mix) {
  created () {
    console.log(this.mixinValue) // -> Hello}}Copy the code
Other parts (components,fliter,directives,Prop,WatchEtc.)
  • The original writing
export default {
  components: {},
  props: {},
  watch: {
    msg (newVal, oldVal) {}
  }
}
Copy the code
  • The rest of the decorator writing is wrapped in the @Component decorator
@Component({
  components: {},
  props: {},
  watch: {
    new (newVal, oldVal) {}
  }
})
export default class HelloWorld extends Vue {}
Copy the code

vue-property-decoratorExtended decorator

@Component(options:ComponentOptions = {})

The @Component decorator comes from vue-class-Component and its function remains unchanged. After using vue-property-derocator, it mainly includes the Component, cache, and other properties that it does not yet support

import {Component,Vue} from 'vue-property-decorator'
import {componentA,componentB} from '@/components'

 @Component({
    components:{
        componentA,
        componentB,
    },
    directives: {
        focus: {
            // The definition of a directive
            inserted: function (el) {
                el.focus()
            }
        }
    }
})
export default class YourCompoent extends Vue{}
Copy the code
@Prop(options: (PropOptions | Constructor[] | Constructor) = {})

The @Prop decorator deals primarily with values from the parent component received by the Prop property

  • Receive three parameters
    • Constructor, such as:String,Number,BooleanAnd so on, the specifiedProptype
    • Constructor[]: specifyPropThe optional type of
    • PropOptions:Propthetype,default,required,validatorSuch as configuration,
  • The original writing
export default{
    props: {propA:String.// propA:Number
        propB:[String.Number].propC: {type:Array.default:(a)= >{
                return ['a'.'b']},required: true.validator:(value) = > {
                return [
                    'a'.'b'].indexOf(value) ! = =- 1}}}}Copy the code
  • @PropDecorator writing
import {Component,Vue,Prop} from vue-property-decorator;

@Component
export default class YourComponent extends Vue {
    @Prop(String)
    propA:string;
    
    @Prop([String.Number])
    propB:string|number;
    
    @Prop({
     type: String.// type: [String , Number]
     default: 'default value'.// Usually String or Number
      // If it is an object or array. The default value is returned from a factory function
      // defatult: () => {
      // return ['a','b']
      // }
     required: true.validator: (value) = > {
        return [
          'InProcess'.'Settled'].indexOf(value) ! = =- 1
     }
    })
    propC:string 
}

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

The @Prosync decorator functions similarly to @Prop, but eventually @Prosync generates a new calculated property

  • Receive two parameters
    • propName: string represents the property name passed by the parent component;
    • options: Constructor | Constructor [] | PropOptions consistent with the first parameter of the @ Prop
    • @PropSyncNeeds to work with the parent component.syncModifier use
  • The original writing
export default {
  props: {
    name: {
      type: String}},computed: {
    syncedName: {
      get() {
        return this.name
      },
      set(value) {
        this.$emit('update:name', value)
      }
    }
  }
}
Copy the code
  • @ProSyncDecorator writing
import { Vue, Component, Prop } from 'vue-property-decorator'

@Component
export default class YourComponent extends Vue {
  @PropSync('name', { type: String}) syncedName! : string }Copy the code
@Model(event? : string, options: (PropOptions | Constructor[] | Constructor) = {})

The @Model decorator handles the Model property of a VUE, which can be customized on a component to achieve bidirectional binding of the prop property of a custom component

  • Receive two parameters
    • event: stringThe event name.
    • options: Constructor | Constructor [] | PropOptions consistent with the first parameter of the @ Prop.

Parent component part (Template part)

<my-input :value="value" @change="val=>value=val"></my-input>
Copy the code

MyInput component section

  • Original (2.2.0+ new)
<template>
  <div class="hello">// Modify prop in the parent method after passing the value directly to the parent method, avoiding modifying prop in the component directly<input type="text" :value="value" @input="$emit('change', $event.target.value)" />
  </div>
</template>
export default {
  model: {
    prop: 'value'.event: 'change'
  },
  props: {
    value: {
      type: String.default: ' '}}}Copy the code
  • @ModelDecorator writing
<template>
  <div class="hello">
    <input type="text" :value="value" @input="$emit('change', $event.target.value)" />
  </div>
</template>

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

@Component
export default class HelloWorld extends Vue {
  @Model('change', {
    type: String}) value! :String
}
Copy the code
@Watch(path: string, options: WatchOptions = {})

The @watch decorator handles the listening properties of the VUE that occur after beforeCreate and before creation

  • Receive two parameters
    • path: Listening properties
    • options?: WatchOptions={}, listening configuration information
      • immediate?: booleanWhether the callback function is called immediately after listening starts;
      • deep?: booleanWhether to call this callback function when the properties of the object being listened on are changed;
  • The original writing
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
  • @watch 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
@Emit(event? : string)

The @emit decorator deals specifically with the $Emit method (the $Emit method is not required to be used here).

  • Received parameter
    • Accepts an optional argument, which is$EmitServes as the event name. If this parameter is not provided, $Emit will call the function name insteadcamelCasetokebab-caseAnd use it as the event name
    • @EmitThe return value of the callback function is taken as the second argument, if the return value is onePromiseObject,$emitWill be inPromiseThe object is marked asresolvedAfter the trigger
    • @EmitThe arguments to the callback function are placed after the return value$emitUse as a parameter.
  • The original writing
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
  • Decorator writing
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
@Ref(refKey? : string)

@ref is a wrapper around the this.$Ref notation, which takes an optional argument to refer to an element or child component. If this parameter is not provided, the property name following the decorator is used as the parameter

  • The original writing
export default {
  computed: {
    loginForm: {
      cache: false,
      get() {
        return this.$refs.loginForm
      }
    },
    passwordForm: {
      cache: false,
      get() {
        return this.$refs.changePasswordForm
      }
    }
  }
}
Copy the code
  • Decorator writing
import { Vue, Component, Ref } from 'vue-property-decorator'
import { Form } from 'element-ui'

@Componentexport default class MyComponent extends Vue { @Ref() readonly loginForm! : Form @Ref('changePasswordForm') readonly passwordForm! : Form public handleLogin() {this.loginForm.validate(valide= > {
      if (valide) {
        // login...
      } else {
        // error tips}}}})Copy the code
@Provide/ @Inject

These two decorators encapsulate the Provide and Inject notation

  • Dojo.provide and Inject

    • When the parent cannot pass data to the child, it passes the dataProvidePass through, and then the child component passes throughInjectIn order to get
    • To allow an ancestor component to inject a dependency into all its descendants, no matter how deep the component hierarchy is, for as long as the upstream and downstream relationship is established
    • Once a property injected by the parent changes, the child component cannot get the change
  • The original writing

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
  • Decorator writing
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
@ProvideReactive/ @InjectReactive

The functions of these two decorators are similar to @provide / @Inject, but the injected properties are reactive, and the child components can get the changes once the injected properties are modified by the parent

  • Decorator writing
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

vuex-classThe use of

@namespaceThe namespace
  • Use decorators directly
@Component
class MyComponent extends Vue{
    @namespace('test').State foo! : string; }Copy the code
  • Reference decorator assignment
const TestModule = namespace("test")

@Component
class MyComponent extends Vue{ @TestModule.State foo! : string; }Copy the code
@StateState mapping (data)
  • Mapping @state foo directly is the same as @state (“foo”) foo
@Component
class MyComponent extends Vue{
    @namespace('test').State foo! : string; }Copy the code
  • Gets the computed state, which, when mapped to the component, is placed under computed and is itself a computed property
@Component
class MyComponent extends Vue{
    /* Only get */ from state
    @namespace('test').State(state= >state.foo) foo! : string;/* Get */ from state and getters
    @namespace('test').State((state,getters) = >state.foo+'getter:'+getters.getFoo) svsgfoo! : string; }Copy the code
  • Use a namespace internally if you do not want to use a namespace externally, you can use arguments to pass the namespace
@Component
class MyComponent extends Vue{
    @State("foo", {namespace:"test"}) foo! : string; }Copy the code
@GetterCalculate attribute

This is similar to State, but does not allow recomputation. Only values can be retrieved

@Component
class MyComponent extends Vue{
    @State("foo", {namespace:"test"}) foo! : string; }Copy the code
@ActionAsynchronous computation, triggered Mutation
@Component
class MyComponent extends Vue{
   @Action("test/setFoo") setFoo! :Function;
}
Copy the code

Action can be used with promise + async/await

/ / the original writing
actions:{
    async queryState({commit},token){
        let result = await Axios.get("url", {data:{ token }})
        commit('state',result.data)
        return result.data
    }
}

// The decorator
@Component
class MyComponent extends Vue{
   private token:string="best"; @Action queryState! :Function;
   
   async onQueryStateClick(){
       let data = await this.queryState(this.token)
       // todo ...}}Copy the code
@MutationCalculate state data directly
@Component
class MyComponent extends Vue{
   @Action("test/setFoo") setFoo! :Function;
}
Copy the code
The original code
export default new Vuex.Store({
  state: { /* State library */ },
  mutations: { /* Sync libraries with commit trigger */ },
  actions: { /* Asynchronous libraries use dispatch to trigger */ },
  getters: { /* Computes attributes */ },
  modules: { /* Submodule */
    test: {
      namespaced: true./* Enable module mode */
      state: {
        foo: "this is foo"
      },
      getters: {
        getFoo(state) { 
          returnstate.foo; }},mutations: { setFoo(state, foo) { state.foo = foo; }},actions: {
        setFoo({ commit }, foo) {
          setTimeout((a)= > {
            commit('setFoo',foo)
          }, 1e3); }}}}})Copy the code