vue中怎么使用ts -- 入门版

7,367 阅读3分钟

最近切换项目,当前项目是vue+ts,开始以为就是加个类型,打开文件一看,有点蒙,做个笔记记录下。

这边是结合vue-property-decorator使用ts。

使用ts的vue项目,和js项目结构是类似的,多了几个文件

  • tsconfig.json: typescript配置文件,主要用于指定待编译的文件和定义编译选项
  • shims-tsx.d.ts: 允许.tsx 结尾的文件,可在 Vue 项目中编写 jsx 代码
  • shims-vue.d.ts: 主要用于 TypeScript 识别.vue 文件,Ts 默认并不支持导入 vue 文件

配合ts使用的库

  • vue-class-component: 类的装饰器
  • vue-property-decorator: 基于 vue 组织里 vue-class-component 所做的拓展import { Vue, Component, Inject, Provide, Prop, Model, Watch, Emit, Mixins } from 'vue-property-decorator'
  • vuex-module-decorators: 用 typescript 写 vuex 很好用的一个库import { Module, VuexModule, Mutation, Action, MutationAction, getModule } from 'vuex-module-decorators'

组件声明

组件声明乍一看有点复杂,以前就是export default {name:'Home',data:...}

现在必须拆分成以下这样:

import { Component, Vue } from "vue-property-decorator";
import HelloWorld from "@/components/HelloWorld.vue"; // @ is an alias to /src

@Component({
  name:'Home'
  components: {
    HelloWorld
  }
})
export default class Home extends Vue {}

data对象

data在ts里是直接展开属性的:

// 可以在上面使用{{name}}
export default class Home extends Vue {
  private name = "哈哈哈";
}

props声明

使用@props


export default class HelloWorld extends Vue {
  // <hello-world msg="颜酱">
  @Prop({ default: "" }) private msg!: string;
}
  • !: 表示一定存在,?: 表示可能不存在。这两种在语法上叫赋值断言

  • @Prop(options: (PropOptions | Constructor[] | Constructor) = {})

    • PropOptions,可以使用以下选项:type,default,required,validator
    • Constructor[],指定 prop 的可选类型
    • Constructor,例如 String,Number,Boolean 等,指定 prop 的类型

methods

直接展开写就行

export default class HelloWorld extends Vue {
  // methods <div @click="clickName">
  public clickName(): void {
    console.log(this.name);
    console.log(this.msg);
  }
}

watch

watch也是分两块:

export default class HelloWorld extends Vue {
  // watch,函数和参数分为两部分,函数名必须是on[key]Change
  @Watch("name", { immediate: true, deep: true })
  private onNameChange(newValue: string, oldValue: string) {
    console.log("watch", newValue, oldValue);
  }
}
  • @Watch(path: string, options: WatchOptions = {})
  • options 包含两个属性 immediate?:boolean 侦听开始之后是否立即调用该回调函数 / deep?:boolean 被侦听的对象的属性被改变时,是否调用该回调函数
  • @Watch('arr', { immediate: true, deep: true }) onArrChanged(newValue: number[], oldValue: number[]) {}

computed

computed直接展开,就是普通方法加个get

export default class HelloWorld extends Vue {
  // computed 就是普通方法前面加个get,表示此属性是计算来的 <div>{{allname}}</div>
  public get allname() {
    return "computed " + this.name;
  }
  set allname(newValue){
      this.name = newValue.slice(8)
  }
}

生命周期函数

生命周期函数就是普通函数的感觉

export default class HelloWorld extends Vue {
  // created生命周期函数
  public created(): void {
    console.log("created");
  }
  // mounted生命周期函数
  public mounted(): void {
    console.log("mounted");
  }
}

注意:写ts版的vue时不要在生命周期中使用其他组件的变量。最好使用js写vue,因为有很多你意想不到的问题……

mixin

ts中写mixin,mixin本身是个ts文件,这点需要注意。

// PeMixin.ts 注意这里的文件命名
import { Component, Vue, Prop } from 'vue-property-decorator';


@Component
export default class PeMixin extends Vue {
  @Prop({ required: true })
  structure: AnyObj;

  created(){
    // ...
  }
}


// 使用mixin的文件
import {
    Component, Prop, Watch, Mixins,
} from 'vue-property-decorator';

// 两个的话,Mixins里面继续添加即可
@Component
export default class Pe extends Mixins(PeiDuiAnswer) {
  // 组件逻辑
}

但是Mixin 在方法里找不到组件中的变量和方法。

emit

emit稍微绕了点:

export default class HelloWorld extends Vue {
  
  /* 以下相当于js时候的 
  clickMsg(){
    this.name='xx';
    this.$emit('change-msg','ddd')
  } 
  当前组件 <div @click="clickMsg">
  父组件 <hello-world :msg="msg" @change-msg="handleChangeMsg">
  handleChangeMsg(value){
    this.msg = value
  }
  
  */
  @Emit("change-msg")
  clickMsg() {
    // 组件本身的逻辑
    this.name = "点击msg 之后 可以修改名字";
    // emit的第二个参数,也就是给父组件的值
    return "ddd";
  }
}
  • @Emit(event?: string)
  • @Emit 装饰器接收一个可选参数,该参数是emit的第一个参数,充当事件名,没有提供这个参数的话,Emit 会将回调函数名的 camelCase 转为 kebab-case,并将其作为事件名
  • @Emit 会将回调函数的返回值作为第二个参数,如果返回值是一个 Promise 对象,$emit 会在 Promise 对象被标记为 resolved 之后触发
  • @Emit 的回调函数的参数,会放在其返回值之后,一起被$emit 当做参数使用

引用