接觸到了新的vue項目,使用vue+ts+vue-property-decotator來進行項目的簡化,一時間語法沒有看懂,所以花時間學習這個裝飾器的包。
1.裝飾器 @Component(options:Component = {})
默認接受一個對象作為參數,在這個對象中聲明components、 filters、 directives等未提供裝飾符的選項,也可以聲明computed、watch等
import { Component, Vue } from 'vue-property-decorator' import Gap from './Gap.vue' @Component({ components: { Gap, } }) export default class CorrectQuestionResult extends Vue{ get trueAnswerText () { const trueAnswer = this.trueAnswer.ecAnswers![0] return this.formatAnswerDesc(trueAnswer.operation!, trueAnswer.source!, trueAnswer.target!) } }
在@component中聲明了引入的組件,組件的寫法也發生了改變,export default class '組件name' extends Vue, 在vue中data、computed的形式也發生改變
<script lang="ts"> import {Vue, Component} from 'vue-property-decorator'; @Component({}) export default class "組件名" extends Vue{ ValA: string = "hello world"; ValB: number = 1; get val() { return this.ValB + 1; } } </script>
等同於
<script> export default { data() { return { ValA: string = "hello world"; ValB: number = 1; } }, computed: { val() { return this.ValB + 1; } } } </script>
2.@Prop(options: (PropOptions | construct[] | construct))
@Prop接受一個參數,可以有三種寫法
Constructor,例如String,Number, Boolean等,指定prop的類型
Constructor[],指定prop的類型
PropOptions,可以使用以下選項:type,default,required,validator
import { Vue, Component, Prop } from 'vue-property-decorator' @Componentexport default class MyComponent extends Vue { @Prop(String) public propA: string | undefined @Prop([String, Number]) public propB!: string | number @Prop({ type: String, default: 'abc' }) public propC!: string }
warning:
屬性的ts類型后面需要加上undefined
類型;或者在屬性名后面加上!,表示非null
和 非undefined
的斷言,否則編譯器會給出錯誤提示
指定默認值必須使用上面例子中的寫法,如果直接在屬性名后面賦值,會重寫這個屬性,並且會報錯。
3.@Model(event?: string, options:(PropOptions | Contructor[] | Constructor) = {})
裝飾自定義Model,自定義v-model,接收兩個參數:1.event 2. prop; 和vue官方的參數一致,只是裝飾器寫法稍有不同。
import { Vue, Component, Model } from 'vue-property-decorator' @Component export default class MyInput extends Vue { @Model('change', { type: String, default: '123' }) public value!: string }
需要在父組件中配合
<input type="text" v-model="value" // 真的 :value="value" // 假的 @change="$emit('change', $event.target.value)" // 假的 />
4.@Watch (path: string, options:watchOptions = {}), 接收兩個參數 path: 被監聽的屬性名, 監聽的條件:{immediate: boolean , 監聽之后是否立即調用該毀掉函數; deep:boolean,被監聽的對象屬性改變,是否調用該函數}
import { Vue, Component, Watch } from 'vue-property-decorator' @Component export default class MyInput extends Vue { @Watch('msg') public onMsgChanged(newValue: string, oldValue: string) {} @Watch('arr', { immediate: true, deep: true }) public onArrChanged1(newValue: number[], oldValue: number[]) {} @Watch('arr') public onArrChanged2(newValue: number[], oldValue: number[]) {} }
5.@Emit裝飾器
1.接收一個可選參數,該參數是$emit的第一個參數(事件名),如果沒有提供這個參數,$emit會將回調函數的cameCase轉為kebab-case,作為事件名
2.會將回調函數的返回值作為第二個參數,如果返回值是一個promise對象,$emit會在promise狀態改為resolve之后觸發。
3.emit回調函數的參數,將會放在其返回值之后,一起被$emit當作參數使用。
import { Vue, Component, Emit } from 'vue-property-decorator' @Component export default class MyComponent extends Vue { count = 0 @Emit() public addToCount(n: number) { this.count += n } @Emit('reset') public resetCount() { this.count = 0 } @Emit() public returnValue() { return 10 } @Emit() public onInputChange(e) { return e.target.value } @Emit() public promise() { return new Promise(resolve => { setTimeout(() => { resolve(20) }, 0) }) } }
等同於
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) }) } } }
6.Mixins在vue中有兩種配合typescript的混合方法,一種需要定義接口、一種不需要定義vue/type/vue模塊
//定義要混合的類 mixins.ts import Vue from 'vue'; import Component from 'vue-class-component'; @Component // 一定要用Component修飾 export default class myMixins extends Vue { value: string = "Hello" }
// 引入 import Component {mixins} from 'vue-class-component'; import myMixins from 'mixins.ts'; @Component export class myComponent extends mixins(myMixins) { // 直接extends myMinxins 也可以正常運行 created(){ console.log(this.value) // => Hello } }
第二種方式,需要定義vue/type/vue模塊,1.改造混入的ts文件定義 vue/type/vue接口
// mixins.ts import { Vue, Component } from 'vue-property-decorator'; declare module 'vue/types/vue' { interface Vue { value: string; } } @Component export default class myMixins extends Vue { value: string = 'Hello' }
import { Vue, Component, Prop } from 'vue-property-decorator'; import myMixins from '@static/js/mixins'; @Component({ mixins: [myMixins] }) export default class myComponent extends Vue{ created(){ console.log(this.value) // => Hello } }
兩種方法的不同是定義vue/type/vue模塊,在混入的時候就要繼承該mixins,,如果是定了該模塊,直接在@Component中混入即可