ts在vue2.0中實(shí)戰(zhàn)
構(gòu)建
通過(guò)官方腳手架構(gòu)建安裝
# 1. 如果沒(méi)有安裝 Vue CLI 就先安裝
npm install --global @vue/cli
最新的Vue CLI工具可以直接使用 TypeScript 集成環(huán)境 創(chuàng)建新項(xiàng)目占业。
運(yùn)行vue create vue-ts
然后,命令行會(huì)要求選擇預(yù)設(shè)熙卡。使用箭頭鍵選擇 Manually select features扁位。
確保選擇了 TypeScript 和 Babel 選項(xiàng)
然后配置其余設(shè)置
設(shè)置完成 vue cli 就會(huì)開(kāi)始安裝依賴(lài)糟需。
目錄解析
安裝完成打開(kāi)項(xiàng)目,集成 ts 后的項(xiàng)目目錄結(jié)構(gòu)是這樣子的:
|-- vue-ts
|-- .browserslistrc # browserslistrc 配置文件 (用于支持 Autoprefixer)
|-- .eslintrc.js # eslint 配置
|-- .gitignore
|-- babel.config.js # babel-loader 配置
|-- package-lock.json
|-- package.json # package.json 依賴(lài)
|-- postcss.config.js # postcss 配置
|-- README.md
|-- tsconfig.json # typescript 配置
|-- vue.config.js # vue-cli 配置
|-- public # 靜態(tài)資源 (會(huì)被直接復(fù)制)
| |-- favicon.ico # favicon圖標(biāo)
| |-- index.html # html模板
|-- src
| |-- App.vue # 入口頁(yè)面
| |-- main.ts # 入口文件 加載組件 初始化等
| |-- shims-tsx.d.ts # 允許.tsx 結(jié)尾的文件荒勇,在 Vue 項(xiàng)目中編寫(xiě) jsx 代碼
| |-- shims-vue.d.ts # 主要用于 TypeScript 識(shí)別.vue 文件萎胰,Ts 默認(rèn)并不支持導(dǎo)入 vue 文件
| |-- assets # 主題 字體等靜態(tài)資源 (由 webpack 處理加載)
| |-- components # 全局組件
| |-- router # 路由
| |-- store # 全局 vuex store
| |-- styles # 全局樣式
| |-- views # 所有頁(yè)面
|-- tests # 測(cè)試
與之前用js構(gòu)建的項(xiàng)目目錄沒(méi)有什么太大的不同,區(qū)別主要是之前 js 后綴的現(xiàn)在改為了ts后綴妆丘,還多了tsconfig.json锄俄、shims-tsx.d.ts、shims-vue.d.ts這幾個(gè)文件
tsconfig.json: typescript配置文件,主要用于指定待編譯的文件和定義編譯選項(xiàng)
shims-tsx.d.ts: 允許.tsx 結(jié)尾的文件勺拣,在 Vue 項(xiàng)目中編寫(xiě) jsx 代碼
shims-vue.d.ts: 主要用于 TypeScript 識(shí)別.vue 文件奶赠,Ts 默認(rèn)并不支持導(dǎo)入 vue 文件
使用
在 vue 中使用 typescript 非常好用的幾個(gè)庫(kù)
vue-class-component: vue-class-component是一個(gè) Class Decorator,也就是類(lèi)的裝飾器
vue-property-decorator: 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 寫(xiě) vuex 很好用的一個(gè)庫(kù)import { Module, VuexModule, Mutation, Action, MutationAction, getModule } from 'vuex-module-decorators'
組件聲明
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
@Component
export default class Test extends Vue {
}
data 對(duì)象
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
@Component
export default class Test extends Vue {
private name = "";
}
Prop 聲明
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
@Component
export default class Test extends Vue {
@Prop({ default: false }) private isCollapse!: boolean;
@Prop({ default: true }) private isFirstLevel!: boolean;
@Prop({ default: "" }) private basePath!: string;
private name = "";
}
- !: 表示一定存在,?: 表示可能不存在药有。這兩種在語(yǔ)法上叫賦值斷言
- @Prop(options: (PropOptions | Constructor[] | Constructor) = {})
- PropOptions毅戈,可以使用以下選項(xiàng):type,default愤惰,required苇经,validator
- Constructor[],指定 prop 的可選類(lèi)型
- Constructor宦言,例如 String扇单,Number,Boolean 等奠旺,指定 prop 的類(lèi)型
method
js 下是需要在 method 對(duì)象中聲明方法蜘澜,現(xiàn)變成
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
@Component
export default class Test extends Vue {
@Prop({ default: false }) private isCollapse!: boolean;
@Prop({ default: true }) private isFirstLevel!: boolean;
@Prop({ default: "" }) private basePath!: string;
private name = "";
public clickFunc(): void {
console.log(this.isCollapse);
console.log(this.basePath);
}
}
Watch 監(jiān)聽(tīng)屬性
@Watch("name", { immediate: true })
private onNameChange(name: string) {
console.log(name);
}
- @Watch(path: string, options: WatchOptions = {})
- options 包含兩個(gè)屬性
- immediate?:boolean 偵聽(tīng)開(kāi)始之后是否立即調(diào)用該回調(diào)函數(shù)
- deep?:boolean 被偵聽(tīng)的對(duì)象的屬性被改變時(shí)施流,是否調(diào)用該回調(diào)函數(shù)
- options 包含兩個(gè)屬性
@Watch('arr', { immediate: true, deep: true })
private onArrChanged(newValue: number[], oldValue: number[]) {}
computed 計(jì)算屬性
public get allname() {
return 'computed ' + this.name;
}
allname 是計(jì)算后的值,name 是被監(jiān)聽(tīng)的值
生命周期函數(shù)
public created(): void {
console.log("created");
}
public mounted(): void {
console.log("mounted");
}
emit 事件
@Emit()
getName() {
return this.name;
}
@Emit()
promise() {
return new Promise(resolve => {
setTimeout(() => {
resolve(20);
}, 0);
});
}
使用 js 寫(xiě)法
getName() {
this.$emit('get-name', this.name)
}
promise() {
const promise = new Promise(resolve => {
setTimeout(() => {
resolve(20)
}, 0)
})
promise.then(value => {
this.$emit('promise', value)
})
}
- @Emit(event?: string)
- @Emit 裝飾器接收一個(gè)可選參數(shù)鄙信,該參數(shù)是emit的第一個(gè)參數(shù)瞪醋,充當(dāng)事件名。如果沒(méi)有提供這個(gè)參數(shù)
Emit 會(huì)將回調(diào)函數(shù)名的 camelCase 轉(zhuǎn)為 kebab-case装诡,并將其作為事件名 - @Emit 會(huì)將回調(diào)函數(shù)的返回值作為第二個(gè)參數(shù)银受,如果返回值是一個(gè) Promise 對(duì)象,$emit 會(huì)在 Promise 對(duì)象被標(biāo)記為 resolved 之后觸發(fā)
- @Emit 的回調(diào)函數(shù)的參數(shù)鸦采,會(huì)放在其返回值之后蚓土,一起被$emit 當(dāng)做參數(shù)使用
vuex
傳統(tǒng)的 store 用法
export default {
namespaced:true,
state:{
foo:""
},
getters:{
getFoo(state){ return state.foo}
},
mutations:{
CHANGE_FOO(state,payload){
state.foo = payload
}
},
actions:{
changeFoo({commit},payload){
commot("getFoo",payload)
}
}
}
vuex-module-decorators的使用方法
// store/test.ts
import {
VuexModule,
Mutation,
Action,
getModule,
Module
} from "vuex-module-decorators";
import store from "@/store";
export interface TestState {
foo: string
}
@Module({ dynamic: true, store, name: "test" })
class Test extends VuexModule implements TestState {
public foo = '';
get getFoo(){
return this.foo
}
@Mutation
private CHANGE_FOO(foo: string) {
this.foo = foo
}
@Action
public changeFoo(foo: string) {
console.log('action:' +foo)
this.CHANGE_FOO(foo);
}
}
export const TestModule = getModule(Test);
- VuexModule 用于基本屬性
class Test extends VuexModule implements TestState {}
-
VuexModule 提供了一些基本屬性,包括
- namespaced
- state
- getters
- modules
- mutations
- actions
- context
@Module 標(biāo)記當(dāng)前為 module
@Module({ dynamic: true, store, name: "test" })
class Test extends VuexModule implements TestState {}
module 本身有幾種可以配置的屬性:
- namespaced:boolean 啟/停用 分模塊
- stateFactory:boolean 狀態(tài)工廠(chǎng)
- dynamic:boolean 在 store 創(chuàng)建之后赖淤,再添加到 store 中蜀漆。開(kāi)啟 dynamic 之后必須提供下面的屬性
- name:string 指定模塊名稱(chēng)
- store:Vuex.Store 實(shí)體 提供初始的 store
- @Mutation 標(biāo)注為 mutation
@Mutation
private CHANGE_FOO(foo: string) {
this.foo = foo
}
- @Action 標(biāo)注為 action
@Action
public changeFoo(foo: string) {
console.log('action:' +foo)
this.CHANGE_FOO(foo);
}
- getModule 得到一個(gè)類(lèi)型安全的 store,module 必須提供 name 屬性
export const UserModule = getModule(User);
在vue文件中調(diào)用
<template>
<div>
<p>store用法</p>
{{ $store.state.test.foo }}
<div><input @change="changeVal" type="text" v-model="fooVal" /></div>
</div>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import { TestModule } from "@/store/test";
@Component
export default class TestStore extends Vue {
private fooVal = "";
private changeVal() {
console.log(TestModule.foo);
TestModule.changeFoo(this.fooVal);
}
}
</script>