Vue + TypeScript 使用 vue-property-decorator 用法總結
簡介
要使vue支持ts寫法,我們需要用到vue-property-decorator,這個組件完全依賴於vue-class-componet
安裝 vue-property-decorator
npm install vue-property-decorator
- 安裝成功之后我們新建HelloWorld.vue
<template>
<div class="hello">
Hello World
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class HelloWorld extends Vue {
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less">
</style>
配置好路由 就可以直接訪問
裝飾器和函數
@Component (完全繼承於vue-class-component)
@Emit
@Inject
@Provice
@Prop
@Watch
@Model
Mixins (在vue-class-component中定義);
@Ref
用法
@Component(options: ComponentOptions = {}) 裝飾器
// options 對象參數可以是
name: 'TsDemo',
components:{},
computed:{},
props:{},
watch: {},
filters: {},
// 等
- 關於事件監聽與觸發,Vue 中提供了 $emit 和 $on, 在vue-property-decorator 中需要使用@Emit
@Emit(event?: string) decorator
import { Vue, Component, Emit } from 'vue-property-decorator'
@Component
export default class YourComponent extends Vue {
count = 0
@Emit()
addToCount(n: number) {
this.count += n
}
@Emit('reset')
resetCount() {
this.count = 0
}
@Emit()
returnValue() {
return 10
}
@Emit()
onInputChange(e) {
return e.target.value
}
@Emit()
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)
})
},
},
}
- 參考例子
新建 父組件emit.vue
<template>
<div>
emit
<Emit2 @handle-emit1="handleEmit1" @test="handleTest"></Emit2>
{{ `子組件點擊${emit2}`}}
</div>
</template>
<script lang="ts">
import {Component, Vue} from "vue-property-decorator";
import Emit2 from './emit2'
@Component({
components: {
Emit2
}
})
export default class Emit extends Vue {
public emit2 = 0;
handleEmit1(val) {
console.log(val)
this.emit2++
}
handleTest(val) {
console.log(val)
}
}
</script>
新建 子組件 emit2.vue
<template>
<div>
emit 子組件
<button @click="onClickEmit1">子組件</button>
</div>
</template>
<script lang="ts">
import {Component, Vue, Emit} from "vue-property-decorator";
@Component
export default class Emit2 extends Vue{
mounted() {
console.log('mounted')
this.$on('handle-emit1', (val) => {
console.log('----- $on 2 接收 ----', val);
})
this.$on('test', (val) => {
console.log('----- $on test 接收 ----', val);
})
}
onClickEmit1 () {
this.handleEmit1('---- ***** -----');
this.handleTest('----- test -------')
}
@Emit()
handleEmit1(n: string) {
console.log('觸發')
}
@Emit('test')
handleTest(n: string) {
console.log('觸發')
}
}
</script>
@Inject
@Provice
- 在Vue中父組件向子組件傳遞值時會用到 props。在vue-property-decorator同樣也有對應的裝飾器 @Prop
我們現在想給子組件傳這樣幾個值
- number 數值
- 有默認值
- 多類型
@Prop
export default class Emit extends Vue {
@Prop()
num!: number;
@Prop({default: 'default'})
str!: string;
@Prop()
numStr!: number | string;
}
computed 計算屬性
<template>
<div>
{{ UserName }}
</div>
</template>
<script lang="ts">
import {Component, Vue, Prop} from "vue-property-decorator";
@Component()
export default class Emit extends Vue {
public firstName: string = 'w';
public lastName: string = 'jx';
get UserName(): string {
return this.firstName + this.lastName;
}
}
</script>
相當於
export default {
computed: {
UserName: function() {
return this.firstName + this.lastName;
}
}
}
@Watch
- @Watch(path: stirng, options: WatchOptions = {}) 裝飾器
//簡單使用
private num: number = 0;
@Watch('num')
numChange(newVal: number, oldVal: number) {
console.log(newVal, oldVal)
}
private obj: Obj = {
name: '1',
one: {
name: '2'
}
}
// 深度監聽
@Watch('obj', {deep: true, immediate: true})
objChange(newVal: Obj, oldVal: Obj) {
console.log(newVal, oldVal);
}
// 監聽對象中的一個屬性值
@Watch('obj.name')
objNameChange(newVal: Obj, oldVal: Obj) {
console.log(newVal, oldVal);
}
private arr: number[] = [];
@Watch('arr', {deep: true})
arrChange(newVal: number[], oldVal: number[]) {
console.log('數組變化', newVal, oldVal);
}
// 直接通過數組索引修改,不能監聽,解決辦法 this.$set(array, index, value);
// this.arr[0] = Math.random() * 10;
// this.$set(this.arr, 0, Math.random() * 10)
- 小結:
1、數組,改變數組的值用Vue的$set方法,改變數組的長度用數組的splice方法使數組變化變成可監聽的。
2、對象。如果操作的屬性是對象內已經有的值,使用$watch,加上關鍵字deep深度監聽對象,如果操作的屬性是對象內沒有的新屬性。使用$set使對象變成可監聽!
@Model
Mixins
//定義要混合的類 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
}
}
@Ref
// - 在 vue-property-decorator 中 訪問子組件方法可以使用
this.$refs.UserMessageComponent.list;
// 直接使用 this 調用,會出現以下錯誤
// Property 'list' does not exist on type 'Vue | Element | (Vue | Element)[]'.
// Property 'list' does not exist on type 'Vue'.
// 解決辦法 第一種方式
(this as any).$refs.UserMessageComponent.list;
(this as any).$refs.UserMessageComponent.del();
// (<UserMessage>this.$refs.UserMessageComponent).del(); 子組件中屬性和方法 訪問權限 public
// 第二種方式
private son: any = null // 存儲 this.$refs.UserMessageComponent
this.son = this.$refs.UserMessageComponent;
this.son.list;
this.son.del();
// 第三種,推薦使用 @Ref 代替
@Ref 裝飾器接收一個可選擇參數,用來指向元素或者子組件引用信息。如果沒有提供參數,會使用裝飾器后面的屬性名作為參數
@Ref(refkey?: string) 參數!: 參數類型;
新建文件index.vue 和 userMessage.vue 兩個文件
// userMessage.vue
<template>
<div class="add_form">
子組件
</div>
</template>
<script lang="ts">
import {Component, Vue, Prop, Watch} from "vue-property-decorator";
@Component
export default class UserMessage extends Vue{
private livePlatList = [];
public list: string = '子組件';
private add(): void {
console.log('------- add -------');
}
publice del(): void {
console.log('------ del -------');
}
}
</script>
<style lang="scss" scoped>
@import "index";
</style>
新建 index.vue
// userMessage.vue
<template>
<div class="add_form">
父組件組件
<UserMessage ref='UserMessageComponent'></UserMessage>
<button @click="handleChildFun">訪問子組件</button>
<button @click="addFormFun" ref="refC">測試ref</button>
</div>
</template>
<script lang="ts">
import {Component, Vue, Ref} from "vue-property-decorator";
import UserMessage from 'userMessage.vue';
@Component({
components: {
UserMessage
}
})
export default class Index extends Vue{
// @Ref(refkey?: string) 參數!: 參數類型; 以下兩種方式都指向 ref="UserMessageComponent" 元素或子組件
@Ref() UserMessageComponent!: UserMessageComponent;
@Ref('UserMessageComponent') UserMessageComponentTow!: UserMessageComponent;
@Ref() readonly refC!: HTMLButtonElement;
private handleChildFun(): void {
this.UserMessageComponent.del();
this.UserMessageComponent.list;
this.UserMessageComponent.livePlatList; // Property 'blivePlatList' is private and only accessible within class 'UserMessage'.
this.refC.innerHTML // this.refC 為button 元素,測試ref
}
}
</script>
<style lang="scss" scoped>
</style>
- vur-router 使用
- vuex 使用
持續更新中。。。