使用 vue-property-decorator 用法總結


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 使用
    持續更新中。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM