前言
TS的一些用法其實官網介紹的很明白了,只不過如何去使用,在項目中如何搭建,
vue-property-decorator
vue-property-decorator
在vue-class-component
的基礎上增加了更多與Vue
相關的裝飾器,使Vue
組件更好的跟TS結合使用。這兩者都是離不開裝飾器的,(decorator)裝飾器已在ES提案中。Decorator
是裝飾器模式的實踐。裝飾器模式呢,它是繼承關系的一個替代方案。動態地給對象添加額外的職責。在不改變接口的前提下,增強類的性能。
vue-property-decorator
是這個Vue項目文件中完全依賴的庫,它是Vue官方推薦的並且依賴於vue-class-component,先介紹下它在項目中的常見用法。
- @Component
- @Emit
- @Provice @Inject
- @Prop
- @Watch
- @Model
- @Minxins
@Component 類裝飾器
首先,Vue頁面中的script部分要加一個lang=ts,這樣安裝好typescript正能引用
<script lang="ts"> import {Vue, Component} from 'vue-property-decorator'; import BaseHeader from '@/components/BaseHeader'; //公共頭部組件 @Component({ components: { BaseHeader } }) export default class extends Vue { private stateA:boolean = true private stateB:string = '' private stateC:number = 0 private stateD:any = {} stateE:any[] = [] } </script>
等同於
<script> import Vue from 'vue'; import BaseHeader from '@/components/BaseHeader'; //公共頭部組件 export default { components: { BaseHeader }, data(){ return { stateA: true, stateB: '', stateC: 0, stateD: {}, stateE: [] } } } </script>
vue-property-decorator
在項目中的應用最主要是起一個裝飾器的作用,差異化的話看對比就非常直觀了
data變量的定義比較多元化,這里區別有加private,不加就是public,當變量標記為private時,它就不能在聲明它的類的外部訪問。
@Component
裝飾器屬性名必須得寫上
@Prop
父子組件之間的屬性傳值
export default class extends Vue { @Prop({ default: 0 }) private propA!: number @Prop({ default: () => [10, 20, 30, 50] }) private propB!: number[] @Prop({ default: 'total, sizes, prev, pager, next, jumper' }) private propC!: string @Prop({ default: true }) private propD!: boolean, @prop([String, Boolean]) propE: string | boolean; }
等同於
export default { props: { propA: { type: Number }, propB: { type: Array, default: [10, 20, 30, 50] }, propC: { type: String, default: 'total, sizes, prev, pager, next, jumper' }, propD: { type: String, default: 'total, sizes, prev, pager, next, jumper' }, propE: { type: [String, Boolean] } } }
這里有兩個常用修飾符!``?
,!
和可選參數?
是相對的, !
表示強制解析(也就是告訴typescript編譯器,我這里一定有值),
你寫?
的時候再調用,typescript
會提示可能為undefined
@Emit
Component export default class YourComponent extends Vue { count = 0 @Emit('reset') resetCount() { this.count = 0 } @Emit() returnValue() { return 10 } @Emit() onInputChange(e) { return e.target.value } }
等同於
export default { data() { return { count: 0 } }, methods: { resetCount() { this.count = 0 this.$emit('reset') }, returnValue() { this.$emit('return-value', 10) }, onInputChange(e) { this.$emit('on-input-change', e.target.value, e) } } }
@Emit裝飾器
的函數會在運行之后觸發等同於其函數名(駝峰式會轉為橫杠式寫法)
的事件, 並將其函數傳遞給$emit
@Emit觸發事件有兩種寫法
- @Emit()不傳參數,那么它觸發的事件名就是它所修飾的函數名.
- @Emit(name: string),里面傳遞一個字符串,該字符串為要觸發的事件名
@Watch 觀察屬性裝飾器
@Watch裝飾器主要用於替代Vue
屬性中的watch
屬性,監聽依賴的變量值變化而做一系列的操作
@Component export default class YourComponent extends Vue { @Watch('child') onChildChanged(val: string, oldVal: string) {} @Watch('person', { immediate: true, deep: true }) onPersonChanged(val: Person, oldVal: Person) {} }
等同於
export default { watch: { child(val, oldVal) {}, person: { handler(val, oldVal) {}, immediate: true, deep: true } } }
watch 是一個對象,對象就有鍵,有值。
- 第一個handler:其值是一個回調函數。即監聽到變化時應該執行的函數。
- 第二個是deep:其值是true或false;確認是否深入監聽。deep的意思就是深入觀察,監聽器會一層層的往下遍歷,給對象的所有屬性都加上這個監聽器(受現代 JavaScript 的限制 (以及廢棄 Object.observe),Vue 不能檢測到對象屬性的添加或刪除)
- 第三個是immediate:其值是true或false;immediate:true代表如果在 wacth 里聲明了之后,就會立即先去執行里面的handler方法,如果為 false就跟我們以前的效果一樣,不會在綁定的時候就執行
@Watch
使用非常簡單,接受第一個參數為要監聽的屬性名, 第二個屬性為可選對象。@Watch所裝飾的函數即監聽到屬性變化之后應該執行的函數。
@Watch
裝飾的函數的函數名並非如上onStateChanged
嚴格命名,它是多元化的,你可以隨心所欲的命名,當然,能按照規范化的命名會使你的代碼閱讀性更好。
// myMixin.ts @Component export default class MyMixin extends Vue { mixinValue:string = 'Hello World!!!' } // 引用mixins import MyMixin from './myMixin.js' @Component export default class extends mixins(MyMixin) { created () { console.log(this.mixinValue) // -> Hello World!!! } }
Minxins
然后我又偷學到了另外一種mixins寫法,記錄一下
先改造一下myMixin.ts
,定義vue/type/vue
模塊,實現Vue接口
// myMixin.ts import { Vue, Component } from 'vue-property-decorator'; declare module 'vue/types/vue' { interface Vue { mixinValue: string; } } @Component export default class myMixins extends Vue { mixinValue: string = 'Hello World!!!' }
引用
import { Vue, Component, Prop } from 'vue-property-decorator'; import MyMixin from './myMixin.js' @Component({ mixins: [MyMixin] }) export default class extends Vue{ created(){ console.log(mixinValue) // => Hello World!!! } }
兩種方式不同在於定義mixins
時如果沒有定義vue/type/vue
模塊, 那么在混入的時候就要繼承該mixins
;
如果定義vue/type/vue
模塊,在混入時可以在@Component
中mixins
直接混入。
@Provide @Inject
@Provide
聲明一個值 , 在其他地方用 @Inject
接收,在實戰項目中用得不多,一般用於不依賴於任何第三方狀態管理庫(如vuex)的組件編寫
@Ref(refKey?: string)
@Ref
裝飾器接收一個可選參數,用來指向元素或子組件的引用信息。如果沒有提供這個參數,會使用裝飾器后面的屬性名充當參數
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 } }) } }
等同於
export default { computed: { loginForm: { cache: false, get() { return this.$refs.loginForm } }, passwordForm: { cache: false, get() { return this.$refs.changePasswordForm } } } }
使用時切記要引入修飾器
import {
Vue,
Component,
Prop,
Component,
Emit,
Provice,
Inject,
Watch,
Model,
Minxins,
} from 'vue-property-decorator'
鈎子函數
以下的public、private
在引入tslint后是必寫的,否則會有警告,如果沒有引的話是可以不寫的
Ts | Js | 說明 |
---|---|---|
public created() {} | created() {} | 初始化 |
public mounted() {} | mounted() {} | 掛載完畢 |
private _getInitData() {} | methods: { _getInitData() {} } | 方法 |
private get _userName() {} | computed: { _userName() {} } | 計算屬性 |
public destroyed() {} | destroyed() {} | 銷毀生命周期 |