TS的一些用法和普通的對比(Vue)
前言
TS的一些用法其實官網介紹的很明白了,只不過如何去使用,在專案中如何搭建,
TS跟正常的Vue專案還是或多或少有不少差距的,js是一門弱型別的語言, 是在變數賦值時,永遠都是給變數直接賦值各種型別值來初始化, 線上一些隱藏的bug就冷不防會暴露出來。把這種錯誤扼殺在專案開發編譯階段而非上線階段, 所有就有了typescript超集的出現。 ts在Vue專案中的基礎用法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() {} | 銷燬生命週期 |