使用 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 使用
    持续更新中。。。
posted @ 2021-11-25 10:13  影的记忆  阅读(2886)  评论(0编辑  收藏  举报