在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編寫它們。
- Class-based components
- Data, props, computed properties, methods, watchers, and emit
- Lifecycle hooks
- Mixins
- 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
提供更對的修飾,例如required
、default
和type
。我們首先從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中編寫複雜的計算屬性,包括getter
和setter
,如下所示。
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
}
我們也可以設置immediate
和deep
watchers 。
@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
,並使用該名稱。由於addData
在CamelCase
中,所以它再次被轉換爲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組件有八個生命週期鉤子,包括created
、mounted
等等,每個鉤子都使用相同的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
庫爲Module
、Mutation
和Action
提供了裝飾器。狀態變量是直接聲明的,就像類變量一樣。這是一個簡單的模塊,它存儲用戶名,並具有一個更改和一個更新用戶名的操作。
我們不需要在Actions
中將state
作爲Mutations
和context
的第一個參數,因爲類庫會處理這個問題。它已經被注入到那些方法中。
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、Mutation
和Action
。
由於我們使用有名稱空間的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/