25 备战2021:vue3 ts开发指南 - AnnGreen1/article GitHub Wiki

备战2021:vue3+ts开发指南

mp.weixin.qq.com前端杨村长 村长学前端

Vue3 + Typescript开发指南

为什么要使用Ts

应不应该使用TS开发Vue3是当前的热门话题,大家主要纠结成本和收益之间的取舍。

什么是TypeScript

官网:构建于JavaScript,增加了静态类型定义

JavaScript变量没有类型,导致代码中各种类型判断语句,冗余度比较高。如果类型没有限制,变量类型可能发生变化,使代码可能出现问题。

图片

ts-01-003.opt.jpg

使用TS的额外成本

image-20210531150655190

是否需要TS

image-20210531151342630

整合vue3+ts

vue cli环境

vuecreatemy-project-

image-20210510114727426

Vite环境

npminit@vitejs/app-

image-20210531151929571

使用TS编写Vue组件

组件定义

<script lang="ts">defineComponent

`

{{ counter }}
- <script lang="ts">- import { defineComponent } from "vue"; export default defineComponent({- data() {- return {- counter: 0- }- },- });- </script>

`

工具支持:Volar

data类型定义

利用类型断言确定数据类型

类型定义

types.d.ts

exporttypeTodo={- id:number;- name:string;- completed:boolean;- }-

Comp.vue

importtype{Todo}from"../types";-

组件定义

<script lang="ts">- export default defineComponent({- data() {- return {- // 利用类型断言- items: [] as Todo[]- }- },- created() {- // 此处会获得类型支持 - this.items.push({- id: 1,- name: 'vue3',- completed: false- })- }- });- </script>-

模板定义

`

-
- {{ item.name }}-
- - `

props类型定义

对象类型利用类型断言和PropType。

类型定义

exporttypeTitleInfo={- value:string;- color:string;- }-

属性定义

`<script lang="ts">- // 属性类型需要PropType支持- import { PropType } from "vue";- import type { TitleInfo } from "../types"

export default defineComponent({- props: {- // 利用泛型类型约束对象类型- titleInfo: Object as PropType,- },- })- </script>

`

模板中使用

<h1:style="{backgroundColor:titleInfo?.color}">{{titleInfo?.value}}</h1>-

<Comp:title-info="{value:'待办事项',color:'#41b883'}"></Comp>-

computed计算属性

标识函数返回类型

computed:{- doubleCounter():number{- returnthis.counter*2- }- },-

methods方法

标识函数形参和返回类型

methods:{- newTodo(todoName:string):Todo{- return{- id:this.items.length+1,- name:todoName,- completed:false,- };- },- addTodo(todo:Todo){- this.items.push(todo);- this.todoName=''- },- },-

data(){- return{- todoName:"",- };- },-

<input- type="text"- v-model="todoName"- @keydown.enter="addTodo(newTodo(todoName))"- />-

Setup Script

setup script方式编写代码会更加简洁

数据定义

`<script setup lang="ts">- import { defineProps, ref, computed } from "vue";

type Todo = {- id: number;- name: string;- completed: boolean;- };

type TitleInfo = {- value: string;- color: string;- };

const items = ref<Todo[]>([]);- items.value.push({- id: 1,- name: "vue3",- completed: false,- });- </script>

`

属性定义

defineProps<{- titleInfo:TitleInfo;- }>();-

计算属性

constcounter=ref(0);- constdoubleCounter=computed(()=>counter.value*2);-

方法

`consttodoName=ref("");

functionnewTodo(todoName:string):Todo{- return{- id:items.value.length+1,- name:todoName,- completed:false,- };- }- functionaddTodo(todo:Todo){- items.value.push(todo);- todoName.value="";- }

`

使用TS编写Vuex

$store类型化

为ComponentCustomProperties扩展$store属性,store/vuex.d.ts

import{Store}from"vuex";

//declareyourownstorestates-
exportinterfaceState{-
counter:number;-
}

declaremodule"@vue/runtime-core"{-
//providetypingsfor`this.$store`-
interfaceComponentCustomProperties{-
$store:Store<State>;-
}-
}

创建Store

store/index.ts

`import{createStore,Store}from"vuex";- import{State}from"./vuex";

conststore=createStore({- state:{- counter:0,- },- });

exportdefaultstore;

`

引入,main.ts

createApp(App).use(store).mount("#app");-

使用,Comp.vue

`import{mapState}from"vuex";

exportdefaultdefineComponent({- props:{- titleInfo:ObjectasPropType,- },- data(){- return{- //counter不需要了- //counter:0,- };- },- computed:{- //映射statecounter- ...mapState(['counter']),- doubleCounter():number{- //$store已经有类型了- returnthis.$store.state.counter*2;- },- },- }

`

useStore()类型化

setup中使用useStore时要类型化,共需要三步:

  1. 定义 InjectionKey

  2. app安装时提供InjectionKey

  3. 传递 InjectionKeyuseStore

store/index.ts

`import{InjectionKey}from"vue";- import{State}from"./vuex";

//defineinjectionkey- exportconstkey:InjectionKey<Store>=Symbol();

`

main.ts

import{key}from"./store";- //作为参数2传入key- createApp(App).use(store,key).mount("#app");-

使用,CompSetup.vue

`import{useStore}from'vuex'- import{key}from'../store'

conststore=useStore()- constcounter=computed(()=>store.state.counter);

`

简化使用

封装useStore,避免每次导入key,store/index.ts

import{useStoreasbaseUseStore}from"vuex";- exportfunctionuseStore(){- returnbaseUseStore(key);- }-

使用变化,CompSetup.vue

import{useStore}from'../store'- conststore=useStore()-

模块化

创建模块文件,store/modules/todo.ts

`import{Module}from"vuex";- import{State}from"../vuex";- importtype{Todo}from"../../types";

constinitialState={- items:[]asTodo[],- };

exporttypeTodoState=typeofinitialState;

exportdefault{- namespaced:true,- state:initialState,- mutations:{- initTodo(state,payload:Todo[]){- state.items=payload;- },- addTodo(state,payload:Todo){- state.items.push(payload)- }- },- actions:{- initTodo({commit}){- setTimeout(()=>{- commit("initTodo",[- {- id:1,- name:"vue3",- completed:false,- },- ]);- },1000);- }- },- }asModule<TodoState,State>;

`

引入子模块,store/index.ts

importtodofrom"./modules/todo";- conststore=createStore({- modules:{- todo,- },- });-

状态中添加模块信息,vuex.d.ts

`importtype{TodoState}from"./modules/todo";

exportinterfaceState{- todo?:TodoState;- }

`

组件中使用,Comp.vue

exportdefault{- data(){- return{- //items:[]asTodo[],- };- },- computed:{- items():Todo[]{- returnthis.$store.state.todo!.items- }- },- methods:{- addTodo(todo:Todo){- //this.items.push(todo);- this.$store.commit("todo/addTodo",todo);- this.todoName="";- },- },- }-

setup中使用,CompSetup.vue

`constitems=computed(()=>store.state.todo!.items)- store.dispatch('todo/initTodo')

functionaddTodo(todo:Todo){- //items.value.push(todo);- store.commit('todo/addTodo',todo)- todoName.value="";- }

`

查看原网页: mp.weixin.qq.com

⚠️ **GitHub.com Fallback** ⚠️