TS語言學習(三)
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後是必寫的,否則會有警告,如果沒有引的話是可以不寫的