preface

After writing some simple syntax of Ts, such as types and attributes, as well as advanced usage of classes, interfaces and decorations, today we will look at how to use Ts in vUE project. At present, most of the company projects are still vue2. X, vUE is an incremental framework. We also want to learn gradually, so this article also first around vue2. X to Ts combat, for the later switch to vue3.0 to lay a foundation.

Introduction to the

Before using, we need to install Ts in the project. The installation process will not be detailed. If we are just learning, we recommend using vUE’s official scaffolding, which has the option of installing Ts. Next, install vue-class-Component and vue-property-decorator

Let’s look at vue-class-Component and vue-property-decorator before we install it

Vue-class-component is the official vUE library that writes components in class mode. This way of writing allows vUE components to use advanced features such as inheritance, mixing, and more importantly, to better use VUE components with TS.

Vue-property-decorator is a community-derived @prop @emit @inject operator based on vue-class-component; Is a superset of UE -class-component to make the code more simple and clear. Directives are required to configure properties that the decorator library does not support, such as Components, filters, directives, etc.

Both are inseparable from the decorator, which is already in the ES proposal. Decorators are an exercise in the decorator pattern. The decorator pattern is an alternative to inheritance. Add additional responsibilities to objects dynamically. Enhance the functionality of a class without changing the interface.

use

Component

Decorators can receive an object as a parameter and declare components, filters, directives, etc. There is no decorator option provided.


<template>
 <div class="home">{{num | addOne (' filters the second parameter ')}}<Test
     ref="helloWorld"
     v-test="'h'"
   />
 </div>
</template>


<script lang='ts'>
import { Component,Vue} from 'vue-property-decorator'
import Test from '@/components/Test.vue'

@Component({
    name: 'Home'./ / component
    components: {
       Test
     },
     
     // Local directives
    directives: {
       test(el: HTMLElement, binding) {
        console.log('DOW:',el,'Local instruction :' ,binding)
       }
    },
    
     // Local filtering
    filters: {
       addOne(num: number, towParam: string) {
         console.log(towParam, 'Local filter')
         return num + 3}}/ / with
     // mixins: [ResizeMixin]
   })

   export default class extends Vue {
      private num: number = 1 // Define a variable
   }
</script>
Copy the code

Tip: To use Ts you need to set the lang property value of the script tag to Ts

The life cycle

 <template>
     <div class="home"></div>
 </template>
    
 <script lang='ts'>
   import { Component, Vue } from 'vue-property-decorator'
   
   @Component({
     name: 'LifeCycle',})export default class extends Vue {
     private num = 1
     private created(): void {
       console.log(this.num)
     }
     private mounted(): void {
       console.log(this.num)
     }
   }
   </script>
Copy the code

Methods, attributes

 <template>
  <div class="home">
    <button @click="addAge">Add 1</button>
    {{ num }}
  </div>
</template>
 
<script lang='ts'>
import { Component, Vue } from 'vue-property-decorator'
@Component({
  name: 'AttrMethod',})export default class extends Vue {
  private num = 1 / / property
  private checked = true

  / / method
  private addAge(): void {
    this.num++
    this.checked = false
  }

  private mounted(): void {
    console.log(this.num)
  }
}
</script>
Copy the code

Computer (Computational properties)

<template>
  <div class="computer">
    {{ count(this.num, 2) }}
    {{ msg }}
  </div>
</template>
 
<script lang='ts'>
import { Component, Vue } from 'vue-property-decorator'
@Component({
  name: 'Computers',})export default class extends Vue {
  private num = 1
  private mounted(): void {
    console.log(this.num)
  }
 /* Computes attributes */

  // Use the following method
  private get count() {
    return function (num: number, numbers: number) {
      return num + numbers
    }
  }

  //
  private get msg() {
    return 'Computational properties of ordinary writing'}}</script>
Copy the code

Watch (listen)

<template>
     <div class="watch">
        {{ num }}
     </div>
</template>

<script lang='ts'>
       import { Component, Vue, Watch } from 'vue-property-decorator'
       @Component({
         name: 'Watch',})export default class extends Vue {
         private num = 1
         private mounted(): void {
           this.timeOut()
         }
         private timeOut() {
           setTimeout(() = > {
             this.num++
           }, 1000)}/ / to monitor
         @Watch('num', { immediate: true.deep: true })
         onNumChange(val: string, old: string) {
           console.log(val, old, 'watch')}}</script>
Copy the code

The onNumChange method should be next to @watch, there should be no code between them, and the method name is optional and not mandatory.

ref

<template>
     <div class="watch">
       <img alt="Vue logo" src=".. /assets/logo.png" ref="img" />
       {{ num }}
       <Test ref="test" />
     </div>
</template>

<script lang='ts'>
   import { Component, Vue, Ref } from 'vue-property-decorator'
   import Test from '@/components/Test.vue'
   @Component({
     name: 'Watch'.components: {
       Test,
     },
   })
   export default class extends Vue {
     private num = 1@Ref() readonly test! : Test// The ref of the imported component
     @Ref('img') readonly img! : HTMLButtonElement// Ref for normal HTML tags
     private mounted(): void {
       console.log(
         'Normal ref usage :'.this.$refs.test,
         'Define how a variable's ref is used :'.this.test,
         'Importing a component's ref'
       )
       console.log(this.img, this.$refs.img, 'Normal IMG tag ref')}}</script>
Copy the code

Dependency injection

  • Provide
<template>
  <div class="home">
    <Inject
      ref="helloWorld"
    />
  </div>
</template>
<script lang='ts'>
// @ is an alias to /src
/*eslint-disable */
import {
  Component,
  Vue,
  Provide,
} from 'vue-property-decorator'
import Inject from '@/components/Inject.vue'

const symbol = Symbol('baz')
// The decorator indicates this
@Component({
  name: 'Provide'.components: {
    Inject
  },
  // mixins: [ResizeMixin]
})
export default class extends Vue {
  @Provide() foo = 'foo' // dependency injection
  @Provide() optional = 'optional' // dependency injection
  @Provide('bar') baz = 'bar'
}
</script>
Copy the code
  • Inject
<template>
  <div class="hello">
    <h1 @click="returnValue">{{ msg }}</h1>
  </div>
</template>

<script lang="ts">
import {
  Component,
  Vue,
  Inject
} from 'vue-property-decorator'
@Component
export default class HelloWorld extends Vue { @Inject() readonly foo! : string// Receive the dependency injection value
  @Inject({ from: 'optional'.default: 'default'}) readonly optional! : string// If the parent component does not pass optional, use default to set the default value
  @Inject('bar') readonly bar! : string private moun ted():void {
    console.log( 22.this.foo, this.optional, this.bar)
  }
}
</script>
Copy the code

Prop

Subgroups receive values from the parent component

  • The parent component
<template>
 <div class="home">

   <Props
     :msg="msg"
     prop-c='11'
    
   />
 </div>
</template>
<script lang='ts'>
// @ is an alias to /src
/*eslint-disable */
import {
 Component,
 Vue,

} from 'vue-property-decorator'
import Props from '@/components/Prop.vue'

const symbol = Symbol('baz')
// The decorator indicates this
@Component({
 name: 'Prop'.components: {
   Props
 },
 
})
export default class extends Vue {
 private msg: string = 'hello'
 private name: string = 'sss'
 private checked: boolean = true
 private num: number = 1
}
</script>
Copy the code
  • Child components
<template>
 <div class="hello">
   <h1 > {{ msg }}</h1>
   <span>{{ propB }}</span>
      <span>{{ propC }}</span>
 </div>
</template>

<script lang="ts">
import {
 Component,
 Prop,
 Vue,
} from 'vue-property-decorator'
@Component
export default class HelloWorld extends Vue { @Prop() private msg! : string/ /! , non-null and undefined
 @Prop(Number) readonly propA: number | undefined
 @Prop({ default: 'default value'}) readonly propB! : string @Prop([String.Boolean]) readonly propC: string | boolean | undefined
}
</script>
Copy the code

Emit

Emits a method to the parent component

  • The parent component

 <template>
  <div class="home">
    <EmitChild
      @return-value="returnValue"
    />
  </div>
</template>
<script lang='ts'>
// @ is an alias to /src
/*eslint-disable */
import {
  Component,
  Vue,

} from 'vue-property-decorator'
import EmitChild from '@/components/Emit.vue'

const symbol = Symbol('baz')
// The decorator indicates this
@Component({
  name: 'Emit'.components: {
    EmitChild
  },
})

export default class extends Vue {
   private returnValue(aa:number):void {
     console.log(aa)
    }
}
</script>
Copy the code
  • Child components
<template>
  <div class="hello">
    <p @click="returnValue">
       emit
    </p>
  </div>
</template>

<script lang="ts">
import {
  Component,
  Vue,
  Emit,
} from 'vue-property-decorator'
@Component
export default class HelloWorld extends Vue {
  @Emit() // The method is emitted so that the parent can use it
  returnValue() {
    return 10}}</script>
Copy the code

PropSync

Implement sync modifier (PROP bidirectional binding)

  • The parent component
<template>
  <div>
    <button @click="exportName">Output the name</button>
    <PropSyncChild
      :name.sync="name"
    />
  </div>
</template>
<script lang='ts'>
// @ is an alias to /src
/*eslint-disable */
import {
  Component,
  Vue,
} from 'vue-property-decorator'
import PropSyncChild from '@/components/PropSync.vue'

// The decorator indicates this
@Component({ 
  name: 'PropSync'.components: {
    PropSyncChild
  },
})
export default class extends Vue {
  private name: string = 'sss'
  exportName():void{
     console.log(this.name)
  }
}
</script>

Copy the code
  • Child components
<template>
  <div class="hello">
    <p @click="setSyncedName">I am a child component: synchronizes, and the child modifies the parent component</p>
  </div>
</template>

<script lang="ts">
import {
  Component,
  Vue,
  PropSync, 
} from 'vue-property-decorator'
@Component
export default class HelloWorld extends Vue {
  @PropSync('name', { type: String}) syncedName! : string// synchronize, which allows the child to modify the value of the parent
  public setSyncedName(): void {
    console.log('PROP bidirectional binding'.)this.syncedName = 'Synchronize, child component modify parent component'}}</script>
Copy the code

Model

Implement V-Model bidirectional binding

  • The parent component
<template>
<div >
  <button @click="setChecked">Modify the checked</button>
  <ModelChild
   v-model="checked"
  />
</div>
</template>
<script lang='ts'>
  import {
    Component,
    Vue,
  } from 'vue-property-decorator'
  import ModelChild from '@/components/Model.vue'
  // The decorator indicates this
  @Component({
    name: 'Model'.components: {
      ModelChild
    },
  })
  export default class extends Vue {
    private checked = false
   setChecked():void{
      this.checked=!this.checked
    }
  }
</script>
Copy the code
  • Child components
<template>
 <div class="hello">I am child component checked: {{checked}}</div>
</template>

<script lang="ts">
   import {
     Component,
     Vue,
     Model,
   } from 'vue-property-decorator'
   @Component
   export default class HelloWorld extends Vue {
     @Model('change', { type: Boolean}) readonly checked! : boolean//v-model
   }
</script>
Copy the code