25 备战2021:vue3 ts开发指南 - AnnGreen1/article GitHub Wiki
mp.weixin.qq.com前端杨村长 村长学前端
应不应该使用TS开发Vue3是当前的热门话题,大家主要纠结成本和收益之间的取舍。
官网:构建于JavaScript,增加了静态类型定义
JavaScript变量没有类型,导致代码中各种类型判断语句,冗余度比较高。如果类型没有限制,变量类型可能发生变化,使代码可能出现问题。
ts-01-003.opt.jpg
image-20210531150655190
image-20210531151342630
vuecreatemy-project-
image-20210510114727426
npminit@vitejs/app-
image-20210531151929571
<script lang="ts">
和 defineComponent
`
`
工具支持:Volar
利用类型断言确定数据类型
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>-
模板定义
`
-对象类型利用类型断言和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:{- doubleCounter():number{- returnthis.counter*2- }- },-
标识函数形参和返回类型
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方式编写代码会更加简洁
`<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="";- }
`
为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/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;- },- },- }
`
setup中使用useStore时要类型化,共需要三步:
-
定义
InjectionKey
-
app安装时提供
InjectionKey
-
传递
InjectionKey
给useStore
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="";- }
`