使用VueCli3+TypeScript+Vuex一步步构建todoList的方法(2)

在根目录下添加 .prttierrc 文件 (应对 prittier 格式化 vue 文件中的 ts 文件时,没办法使用 tslint 规则进行格式化,需要对它单独处理,以免 tslint 报错)

{ "singleQuote": true }

shims-vue.d.ts

declare module "*.vue" { import Vue from "vue"; export default Vue; }

声明所有以 .vue 结尾的文件,默认导入 vue ,默认导出 Vue,用以在项目中ts文件识别 .vue 结尾文件。

在 main.ts 中,引入一个 vue 组件必须以 .vue 结尾。

import Vue from 'vue'; import App from './App.vue'; import router from './router'; import store from './store'; Vue.config.productionTip = false; new Vue({ router, store, render: (h) => h(App), }).$mount('#app');

Vue class

vue-property-decorator

写一个 todolist 组件顺便来介绍 vue-property-decorator,为了方便页面构建,使用 element-ui

element-ui 使用 ts 开发,默认有 .d.ts 的声明文件

npm i element-ui

// main.ts import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI);

在 /src/compenents/ 新建 todoList.vue , 代码如下:

<template> <div> <el-card> <div slot="header"> <el-row :gutter="18"> <el-col :span="18"> <el-input v-model="todo" placeholder="请输入内容" ></el-input> </el-col> <el-col :span="2"> <el-button type="primary" icon="el-icon-circle-plus-outline" @click="addItem" >add</el-button> </el-col> </el-row> </div> <div v-for="(item,index) in todoList" :key="item" @click="removeItem(index)" >{{ item }}</div> </el-card> <label >{{todoLength}} records</label> </div> </template>

<script lang="ts"> import { Component, Prop, Vue, Emit } from 'vue-property-decorator'; @Component export default class HelloWorld extends Vue { public todo: string = ''; @Prop({ default: [] }) private readonly todoList!: string[]; get todoLength(): number { return this.todoList.length; } @Emit() private addItem(): string | undefined { if (this.todo) { return this.todo; } } @Emit('removeItem') private removeItem(index: number): number { return index; } } </script>

<!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped lang="scss"> .todo_list { display: flex; justify-content: center; flex-direction: column; align-items: center; .box-card { width: 480px; } .text { font-size: 14px; text-align: left; } .item { margin-bottom: 18px; } } </style>

对 ts 代码的用法指出以下几点:

prop 建议写成 xxx!: type 的形式,不然要写成 xxx : type | undefined

@Emit 可以不传参数,emit 出去的事件名默认是修饰的函数名,但是当函数的命名规则为 camelCase 时需要注册的函数名必须是 kebab-case

@Emit 传参是由修饰的函数 return value

改造 Home.vue 如下:

<template> <div> <todoList :todoList="[]" @add-item="addTodoList" @removeItem="addTodoLisItem" /> </div> </template> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator'; import todoList from '@/components/todoList.vue'; // @ is an alias to /src import { State, Getter, Action } from 'vuex-class'; @Component({ components: { todoList } }) export default class Home extends Vue { public addTodoList(val: string) { console.log(val); } private created() { console.log('i add life cycle funciton -- created'); } private addTodoLisItem(index: number) { console.log(index); } } </script>

Vuex

有关 ts 中的 vuex 的写法要从vuex-class 说起,在 官方的 vue-property-decorator 中也推荐使用该库。

npm i vuex-class

在 src 文件夹中新建 store 文件夹, 在 store 新建 index.ts,todoList.ts

// index.ts import Vue from 'vue'; import Vuex from 'vuex'; import todolist from './todoList'; Vue.use(Vuex); export default new Vuex.Store({ modules: { todolist } });

// todoList.ts import { Commit, Dispatch, GetterTree, ActionTree, MutationTree } from 'vuex'; const ADD_TODOLIST = 'ADD_TODOLIST'; const REMOVE_ITEM = 'REMOVE_ITEM'; export interface RootState { version: string; } interface Payload { [propName: string]: any; } interface TodoListType { todoList: string[]; } interface Context { commit: Commit; dispatch: Dispatch; } const dataSource: TodoListType = { todoList: [] }; const getters: GetterTree<TodoListType, RootState> = { getTodoList(state: TodoListType): string[] { return state.todoList; } }; const mutations: MutationTree<TodoListType> = { ADD_TODOLIST: (state: TodoListType, item: string) => { console.log(item); state.todoList.push(item); }, REMOVE_ITEM: (state: TodoListType, removeIndex: number) => { state.todoList = state.todoList.filter((item: string, index: number) => { return removeIndex !== index; }); } }; const actions: ActionTree<TodoListType, RootState> = { addList: async ({ commit }: Context, item: string) => { await Promise.resolve( setTimeout(() => { commit(ADD_TODOLIST, item); }, 100) ); }, removeItem: async ({ commit }: Context, { index }: Payload) => { await Promise.resolve( setTimeout(() => { commit(REMOVE_ITEM, index); }, 100) ); } }; export default { namespaced: true, state: dataSource, getters, mutations, actions };

删除原来与 main.ts 同级的 store.ts

对 todoList.ts 需要注意以下几点:

对于 getters 、mutations 、actions 响应的 type 可以使用 command + 左键点击 进入声明文件查看,也可以不指定 type ,但是建议写上

对于 Payload 解构  tslint 报错的,可以为 Payload 添加类型声明

interface Payload { [propName: string]: any; }

代码中的 dataSource 本意为 state ,但是不能用 state 命名,tslint 会和形参 state 冲突

改造 /views/Home.vue 如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/cb5a84cc4cf3d177a0045a2cc937512e.html