Skip to main content

在Vue2项目中使用TypeScript

· 预计阅读时间:5 分钟
note

在Vue2项目中使用TypeScript,相关配置和语法

1、Vue2.x使用TypeScript#

1.1、安装依赖#

npm i typescript  ts-loader vue-class-component vue-property-decorator vuex-class 

(1) ts-loadertypescript使用typescript必须的#

(2) vue-class-component 可以把组件写成 class 的模式,自定义装饰器,路由钩子#

(3) vue-property-decorator 提供这些装饰器#

@Prop@PropSync@Model@ModelSync@Watch@Provide@Inject@ProvideReactive@InjectReactive@Emit@Ref@VModel@Component //由 vue-class-component 提供Mixins //由 vue-class-component 提供

vue-class-component和vue-property-decorator区别

import Component from 'vue-class-component';import { Component } from 'vue-property-decorator'

这里的 vue-property-decorator 此库完全依赖于 vue-class-component,所以都有 Component

(4) vuex-class 提供class组件的VueX的支持#

2、用ts实现的组件中使用VueX#

2.1、创建VueX文件#

  • @/store/index.ts
import Vue from "vue";import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({  state: {    foo:""  },  getters: {    foo: state => {      return state.foo+"你好"    }  }  mutations: {    foo(state,value){      state.foo=value    }  },  actions: {    foo(context,value){      setTimeout(() => {        commit('foo',value)      }, 1000)    }  },  modules: {},});

2.2、ts组件中使用VueX#

import { Component, Ref, Vue } from "vue-property-decorator";import {  State,  Getter,  Action,  Mutation,  namespace} from 'vuex-class' const someModule = namespace('path/to/module') @Componentexport class MyComp extends Vue {  @State('foo') stateFoo  @State(state => state.bar) stateBar  @Getter('foo') getterFoo  @Action('foo') actionFoo  @Mutation('foo') mutationFoo  @someModule.Getter('foo') moduleGetterFoo   // If the argument is omitted, use the property name   //如果省略参数,请使用属性名称  // for each state/getter/action/mutation type  //对于每个状态/getter/action/mutation类型  @State foo  @Getter bar  @Action baz  @Mutation qux   created () {    this.stateFoo // -> store.state.foo    this.stateBar // -> store.state.bar    this.getterFoo // -> store.getters.foo    this.actionFoo({ value: true }) // -> store.dispatch('foo', { value: true })    this.mutationFoo({ value: true }) // -> store.commit('foo', { value: true })    this.moduleGetterFoo // -> store.getters['path/to/module/foo']  }}

3、使用ts实现组件的装饰器用法#

3.1、@Component#

  • @Component(options) 的options 是配置 decorator 库不支持的属性, 如:name, components, filters, directives等
<template>  <div id="app">  </div></template>
<script lang="ts">import { Component, Vue } from 'vue-property-decorator';
import test from './components/test.vue'
@Component({  name:"",  components: {    test,  },})export default class Demo extends Vue {  }</script>
import { Component, Vue } from "vue-property-decorator";@Componentexport default class Home extends Vue {}

3.2、data#

  • data的的数据可以直接写在类中
import { Vue, Component, Prop } from 'vue-property-decorator' @Componentexport default class Demo extends Vue {  //public(公共的任何地方被访问到,默认所有的属性和方法都是 public)   //private (私有的,不能在声明它的类的外部访问,子类中也不允许被访问的)  //protected (受保护的,它和 private 类似,区别是它在子类中是允许被访问的)  public isDone: boolean = false;  private decLiteral: number = 6;  protected name: string = "bob";   //不写访问修饰符默认是public修饰符  list1: number[] = [1, 2, 3];  list2: Array<number> = [1, 2, 3];    //类型推断(不写明类型时会自动根据赋值推断类型)  isDone = false;  decLiteral = 6;  name = "bob";  list1:= [1, 2, 3];  zoo= {};}

3.3、method#

  • 直接写方法名,有返回数据写返回数据类型,有参数写参数类型
import { Vue, Component } from 'vue-property-decorator' @Componentexport default class Demo extends Vue {  blindBoxItems1(){
  }  blindBoxItems2():String {
  }  blindBoxItems3(item:any):String {
  }}

3.4、计算属性#

  • 计算属性方法,在方法前加get关键字表示,其余和method是一样的
import { Vue, Component } from 'vue-property-decorator' @Componentexport default class Demo extends Vue {  get blindBoxItems1():String {
  }  get blindBoxItems2(item:any):String {
  }}

3.5、生命周期函数#

  • 和method是一样的直接写在类中
import { Vue, Component } from 'vue-property-decorator' @Componentexport default class Demo extends Vue {  created(){
  }  mounted(){
  }}

3.6、@Prop#

import { Vue, Component, Prop } from 'vue-property-decorator' @Componentexport default class YourComponent extends Vue {  @Prop(Number) readonly propA: number | undefined  @Prop({ default: 'default value' }) readonly propB!: string  @Prop({ type: String, default: 'default value' }) readonly propC!: string  @Prop([String, Boolean]) readonly propD: string | boolean | undefined  //断言是number  @Prop() age!: number}

3.7、@PropSync#

  • 可实现Prop双向绑定
import { Vue, Component, PropSync } from 'vue-property-decorator' @Componentexport default class YourComponent extends Vue {  @PropSync('name', { type: String }) syncedName!: string}

原始非ts组件写法

export default {  props: {    name: {      type: String,    },  },  computed: {    syncedName: {      get() {        return this.name      },      set(value) {        this.$emit('update:name', value)      },    },  },}

3.8、@Watch#

import { Vue, Component, Watch } from 'vue-property-decorator' @Componentexport default class YourComponent extends Vue {  //当child改变时会自动调用onChildChanged方法  @Watch('child')  onChildChanged(val: string, oldVal: string) {}
  //当person改变时会自动调用onChildChanged方法和onPersonChanged2方法(监听到一个改变执行两个不同的方法)  @Watch('person', { immediate: true, deep: true })  onPersonChanged1(val: Person, oldVal: Person) {}  @Watch('person')  onPersonChanged2(val: Person, oldVal: Person) {}}

原始非ts写法

export default {  watch: {    child: [      {        handler: 'onChildChanged',        immediate: false,        deep: false,      },    ],    person: [      {        handler: 'onPersonChanged1',        immediate: true,        deep: true,      },      {        handler: 'onPersonChanged2',        immediate: false,        deep: false,      },    ],  },  methods: {    onChildChanged(val, oldVal) {},    onPersonChanged1(val, oldVal) {},    onPersonChanged2(val, oldVal) {},  },}

3.9、@Emit#

  • @Emit装饰器接收一个可选参数,作为事件名;如果没有提供这个参数,$emit会将回调函数的camelCase(驼峰式)转为kebab-case(短横线命名),并将其作为事件名;父组件中使用时监听该事件名即可

  • @Emit会将回调函数的返回值作为第二个参数,如果返回值是一个Promise对象,$emit会将Promise对象状态为resolved之后触发;

  • @Emit的回调函数的参数,会放在其返回值之后,一起被$emit当作参数使用;

import { Vue, Component, Emit } from 'vue-property-decorator' @Componentexport 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)    })  }}

3.10、@Ref#

import { Vue, Component, Emit } from 'vue-property-decorator'@Componentexport default class YourComponent extends Vue {  @Ref("blind_box") readonly blind_box!: HTMLButtonElement;  getBlindBox() {    this.blind_box.style.width = this.width + "px";    this.blind_box.style.height = this.height + "px";  }}