在Vue中使用typescript

注:本文为翻译文章,非原创,文章原文链接在末尾附上。因为最近项目中需要在vue中使用typescript,查了很多资料,大部分都是一笔带过,没有特详细的资料,直到朋友发了这个链接给我,简直是宝藏文章啊。本人vue还是个小白,翻译中有词不达意的地方,敬请指正。

Vue是一个惊人的、轻量级的、渐进的前端框架。因为Vue是灵活的,所以用户不必使用TypeScript。与Angular不同的是,旧版本的Vue对TypeScript没有适当的支持。因此,大多数Vue应用程序都是用JavaScript编写的。

现在有了对TypeScript的官方支持,就可以使用Vue CLI从头创建TypeScript项目了。然而,我们仍然需要一些带有自定义装饰器和特性的第三方包来创建一个真正的、完整的TypeScript应用程序,并且官方文档并不包含开始时需要的所有信息。

为了帮助更全面地描述,我们将演示如何使用Vue CLI构建一个新的Vue + TypeScript应用程序。

getting start

从下面这行代码开始

vue create typescript-app

选择手动选择功能并如下所示进行配置。
在这里插入图片描述

在项目设置之后,我们将运行项目来测试它一次。

cd typescript-app
npm run serve

打开localhost:8080(或您的控制台在启动项目后显示的URL),我们可以看到它成功运行。

随着本教程的深入,我们将回顾以下内容,并展示如何使用TypeScript编写它们。

  1. Class-based components
  2. Data, props, computed properties, methods, watchers, and emit
  3. Lifecycle hooks
  4. Mixins
  5. Vuex

打开HelloWorld。组件目录中的vue文件,您将看到如下所示的结构。

注意:对于每个实例,我将同时显示TypeScript和javascript等价的代码,以便您可以轻松地比较两者。让我们开始吧!

1.Class-based components

//Typescript code
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component
export default class HelloWorld extends Vue {
}
</script>

JavaScript的等效代码:

<script>
export default {
name: 'HelloWorld'
}
</script>

要使用TypeScript,首先需要将

vue-property-decorator是一个第三方包,它使用官方的vue-class-component组件包,并在此基础上添加了更多的装饰器。我们也可以显式地使用name属性来命名组件,但是使用它作为类名就足够了。

@component({
  name: 'HelloWorld'
})

Importing a component(引入组件)

在其他组件中注册组件的代码是在@Component装饰器中编写的,如下所示。

<template>
  <div class="main">
    <project />
  </div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import Project from '@/components/Project.vue'
@Component({
  components: {
    project
  }
})
export default class HelloWorld extends Vue {
}
</script>

JavaScript等效代码:

<template>
  <div class="main">
    <project />
  </div>
</template>
<script>
import Project from '@/components/Project.vue'
export default {
  name: 'HelloWorld',
  components: {
    project
  }
})
</script>

2. Data, props, computed properties, methods, watchers, and emit

Using data

为了使用data属性,我们可以简单地将它们声明为类变量。

@Component
export default class HelloWorld extends Vue {
  private msg: string = "welcome to my app"
  private list: Array<object> = [
    {
      name: 'Preetish',
      age: '26'
    },
    {
      name: 'John',
      age: '30'
    }
  ]
}

JavaScript等效代码:

export default {
  data() {
    return {
      msg: "welcome to my app",
      list: [
        {
          name: 'Preetish',
          age: '26'
        },
        {
          name: 'John',
          age: '30'
        }
      ]
    }
}

Using props

我们可以使用@Prop装饰器来使用Vue组件中的props。在Vue中,我们可以为props提供更对的修饰,例如requireddefaulttype。我们首先从vue-property-decorator中导入道具装饰器,并将其编写为如下所示。我们还可以使用readonly来避修改props

import { Component, Prop, Vue } from 'vue-property-decorator'
@Component
export default class HelloWorld extends Vue {
  @Prop() readonly msg!: string
  @Prop({default: 'John doe'}) readonly name: string
  @Prop({required: true}) readonly age: number
  @Prop(String) readonly address: string
  @Prop({required: false, type: String, default: 'Developer'}) readonly job: string
}
</script>

JavaScript等效代码:

export default {
  props: {
    msg,
    name: {
      default: 'John doe'
    },
    age: {
      required: true,
    },
    address: {
      type: String
    },
    job: {
      required: false,
      type: string,
      default: 'Developer'
    }
  }
}

Computed properties

计算属性Computed用于编写简单的模板逻辑,例如操作、附加或连接数据。在TypeScript中,一个普通的计算属性也以get关键字为前缀。

export default class HelloWorld extends Vue {
  get fullName(): string {
    return this.first+ ' '+ this.last
  }
}

JavaScript等效代码:

export default {
  fullName() {
    return this.first + ' ' + this.last
  }
}

我们可以在TypeScript中编写复杂的计算属性,包括gettersetter,如下所示。

export default class HelloWorld extends Vue {
  get fullName(): string {
    return this.first+ ' '+ this.last
  }
  set fullName(newValue: string) {
    let names = newValue.split(' ')
    this.first = names[0]
    this.last = names[names.length - 1]
  }
}

JavaScript等效代码:

fullName: {
  get: function () {
    return this.first + ' ' + this.last
  },
  set: function (newValue) {
    let names = newValue.split(' ')
    this.first = names[0]
    this.last = names[names.length - 1]
  }
}

Methods

与普通类方法一样,TypeScript中的方法也有一个可选的访问修饰符。

export default class HelloWorld extends Vue {
  public clickMe(): void {
    console.log('clicked')
    console.log(this.addNum(4, 2))
  }
  public addNum(num1: number, num2: number): number {
    return num1 + num2
  }
}

JavaScript等效代码:

export default {
  methods: {
    clickMe() {
      console.log('clicked')
      console.log(this.addNum(4, 2))
    }
    addNum(num1, num2) {
      return num1 + num2
    }
  }
}

Watchers

watchers的编写方式与我们通常用JavaScript编写的方式不同。在JavaScript中,watcher 最常用的语法是:

watch: {
  name: function(newval) {
    //do something
  }
}

我们不经常使用handler 语法.

watch: {
  name: {
    handler: 'nameChanged'
  }
}
methods: {
  nameChanged (newVal) {
    // do something
  }
}

然而,TypeScript语法类似于第二个方法。在TypeScript中,我们使用@Watch装饰器并传递需要监视的变量的名称。

@Watch('name')
nameChanged(newVal: string) {
  this.name = newVal
}

我们也可以设置immediatedeepwatchers 。

@Watch('project', { 
  immediate: true, deep: true 
})
projectChanged(newVal: Person, oldVal: Person) {
  // do something
}

JavaScript等效代码:

watch: {
  person: {
      handler: 'projectChanged',
      immediate: true,
      deep: true
    }
}
methods: {
  projectChanged(newVal, oldVal) {
    // do something
  }
}

Emit

要将一个方法从子组件发送到父组件,我们将在TypeScript中使用@Emit装饰器。

@Emit()
addToCount(n: number) {
  this.count += n
}
@Emit('resetData')
resetCount() {
  this.count = 0
}

在第一个示例中,将函数名addToCount转换为kebabb -case,这与Vue中的emit工作方式非常相似。

在第二个示例中,我们传递了方法的显式名称resetData,并使用该名称。由于addDataCamelCase中,所以它再次被转换为kebabo-case

<some-component add-to-count="someMethod" />
<some-component reset-data="someMethod" />

JavaScript等效代码:

 methods: {
    addToCount(n) {
      this.count += n
      this.$emit('add-to-count', n)
    },
    resetCount() {
      this.count = 0
      this.$emit('resetData')
    }
}

3. Lifecycle hooks(生命周期钩子)

一个Vue组件有八个生命周期钩子,包括createdmounted等等,每个钩子都使用相同的TypeScript语法。这些被声明为普通的类方法。因为生命周期钩子是自动调用的,所以它们既不接受参数,也不返回任何数据。因此,我们不需要访问修饰符、输入参数或返回类型。

export default class HelloWorld extends Vue {
  mounted() {
    //do something
  }
  beforeUpdate() {
    // do something
  }
}

JavaScript等效代码:

export default {
  mounted() {
    //do something
  }
  beforeUpdate() {
    // do something
  }
}

4. Mixins

为了在TypeScript中创建mixin,我们必须首先创建mixin文件,该文件包含了我们与其他组件共享的数据。

在mixin目录下创建一个名为ProjectMixin.ts的文件,并添加以下mixin,它共享项目名称和更新项目名称的方法。

import { Component, Vue } from 'vue-property-decorator'
@Component
class ProjectMixin extends Vue {
  public projName: string = 'My project'
  public setProjectName(newVal: string): void {
    this.projName = newVal
  }
}
export default ProjectMixin

JavaScript等效代码:

export default {
  data() {
    return {
      projName: 'My project'
    }
  },
  methods: {
    setProjectName(newVal) {
      this.projName = newVal
    }
  }
}

要在我们的Vue组件中使用上面的mixin,我们需要从Vue -property-decorator和mixin文件本身中导入Mixins,并按如下方式编写它。

//Projects.vue
<template>
  <div class="project-detail">
    {{ projectDetail }}
  </div>
</template>
<script lang="ts">
import { Component, Vue, Mixins } from 'vue-property-decorator'
import ProjectMixin from '@/mixins/ProjectMixin'
@Component
export default class Project extends Mixins(ProjectMixin) {
  get projectDetail(): string {
    return this.projName + ' ' + 'Preetish HS'
  }
}
</script>

JavaScript等效代码:

<template>
  <div class="project-detail">
    {{ projectDetail }}
  </div>
</template>
<script>
import ProjectMixin from '@/mixins/ProjectMixin'
export default {
  mixins: [ ProjectMixin ],
  computed: {
    projectDetail() {
      return this.projName + ' ' + 'Preetish HS'
    }
  }
}
</script>

5. Vuex

Vuex是大多数Vue.js应用程序中使用的官方状态管理库。将存储划分为有名称空间的模块是一个很好的实践。我们将演示如何在TypeScript中编写它。

首先,我们需要安装两个流行的第三方软件包:

npm install vuex-module-decorators -D
npm install vuex-class -D

store文件夹中,让我们创建一个module文件夹来放置每个有名称空间的store模块。

创建一个名为user.ts的文件保存用户状态。

// store/modules/user.ts
import { VuexModule, Module, Mutation, Action } from 'vuex-module-decorators'
@Module({ namespaced: true, name: 'test' })
class User extends VuexModule {
  public name: string = ''
  @Mutation
  public setName(newName: string): void {
    this.name = newName
  }
  @Action
  public updateName(newName: string): void {
    this.context.commit('setName', newName)
  }
}
export default User

vuex-module-decorators库为ModuleMutationAction提供了装饰器。状态变量是直接声明的,就像类变量一样。这是一个简单的模块,它存储用户名,并具有一个更改和一个更新用户名的操作。

我们不需要在Actions中将state作为Mutationscontext的第一个参数,因为类库会处理这个问题。它已经被注入到那些方法中。

JavaScript等效代码:

export default {
  namespaced: true,
  state: {
    name: ''
  },
  mutations: {
    setName(state, newName) {
      state.name = newName
    }
  },
  actions: {
    updateName(context, newName) {
      context.commit('setName', newName)
    }
  }
}

在store文件夹中,我们需要创建一个index.ts文件,初始化vuex和注册module:

import Vue from 'vue'
import Vuex from 'vuex'
import User from '@/store/modules/user'
Vue.use(Vuex)
const store = new Vuex.Store({
  modules: {
    User
  }
})
export default store

Using Vuex in components(组件中使用Vuex)

要使用Vuex,我们可以利用一个名为vuex-class的库。这个库提供装饰器来绑定Vue组件中的State、Getter、MutationAction

由于我们使用有名称空间的Vuex模块,所以我们首先从 vuex-class 中导入namespace,然后传递模块的名称来访问该模块。

<template>
  <div class="details">
    <div class="username">User: {{ nameUpperCase }}</div>
    <input :value="name" @keydown="updateName($event.target.value)" />
  </div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import { namespace } from 'vuex-class'
const user = namespace('user')
@Component
export default class User extends Vue {
  @user.State
  public name!: string

  @user.Getter
  public nameUpperCase!: string

  @user.Action
  public updateName!: (newName: string) => void
}
</script>

JavaScript等效代码:

<template>
  <div class="details">
    <div class="username">User: {{ nameUpperCase }}</div>
    <input :value="name" @keydown="updateName($event.target.value)" />
  </div>
</template>
<script>
import { mapState, mapGetters, mapActions} from 'vuex'
export default  {
  computed: {
    ...mapState('user', ['name']),
    ...mapGetters('user', ['nameUpperCase'])
  }  
  methods: {
    ...mapActions('user', ['updateName'])
  }
}
</script>

结语

现在,您已经拥有了在TypeScript中完全创建Vue.js应用程序所需的所有基本信息,使用一些官方和第三方库来充分利用类型化和自定义装饰器特性。Vue 3.0将更好地支持TypeScript开箱即用,而且整个Vue.js代码都在TypeScript中重写,以提高可维护性。

一开始,使用TypeScript似乎有点困难,但是当你习惯了之后,你的代码中就会有更少的bug,并且在使用相同代码的其他开发人员之间的协作也会更顺畅。

原文地址:https://blog.logrocket.com/how-to-write-a-vue-js-app-completely-in-typescript/

Logo

前往低代码交流专区

更多推荐