Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

41. Vue 实战:TypeScript 下的 Vuex #42

Open
hello-chinese opened this issue Sep 27, 2021 · 0 comments
Open

41. Vue 实战:TypeScript 下的 Vuex #42

hello-chinese opened this issue Sep 27, 2021 · 0 comments
Labels
typescript学习 Improvements or additions to documentation

Comments

@hello-chinese
Copy link
Owner

Vue 实战:TypeScript 下的 Vuex

我们已经基本完成了 UI 层面的编写,接下来我们需要对逻辑层进行实现。

我们选择全局状态管理工具 vuex,但是在 TypeScript 中 vuex 往往要与 vuex-class 进行配合,它同样提供了多个装饰器供我们使用。

首先安装 vuex-class:

npm i -S vuex-class

本节对应源代码在v1.2

创建 todo 任务逻辑

我们可以 src/store/state.ts 中先定义 State 的类型和初始值。

export enum Mode {
  edit, // 处于编辑状态
  finish // 处于编辑完成状态
}

export interface ITodoItem {
id: string; // todo任务的id
name: string; // todo 任务名称
isDone: boolean; // 任务是否完成
iconName: string; // 任务的图标
color: string; // 任务底色
mode: Mode; // 编辑状态
}

export interface State {
todoList: Array<ITodoItem>;
}

export const state: State = {
todoList: []
};

然后我们在 src/store/mutations.ts 中编写创建 todo 的逻辑,其实很简单,我们接受一个 todo 对象,把它添加到 todoList 数组中即可。

export const mutations: MutationTree<State> = {
  // 创建 todo
  createTodoItem(state: State, todoItem: ITodoItem) {
    state.todoList.push(todoItem);
  },
};

那么如何在组件中使用 mutations 呢?

import { Component, Prop, Vue } from "vue-property-decorator";
import { Icon } from "vant";
import { Mutation, State } from "vuex-class";
import { ITodoItem, Mode } from "../store/state";
import { _ } from "../utils";
@Component({
  components: {
    [Icon.name]: Icon
  }
})
export default class Header extends Vue {
  @State private todoItem!: ITodoItem[];
  @Mutation private createTodoItem!: (todo: ITodoItem) => void;

  private createTodoItemHandle() {
    const newItem: ITodoItem = {
      id: _.uuid(),
      name: "新任务",
      isDone: false,
      mode: Mode.edit,
      iconName: "yingtao",
      color: "#FFCC22"
    };
    this.createTodoItem(newItem);
  }

}

我们看到 @mutation 就是 vuex-class 提供的装饰器,它可以帮助我们把相关的 mutations 作为类成员来使用。

自定义 todo 内容

我们可以先看一下动图的演示:

我们点击了 + 按钮之后创建了新的 todo 任务,然后进入了自定义 todo 任务的编辑页面,我们可以选择背景颜色和图标,也可以自定义任务名称。

这些逻辑我们统一在 mutations 中实现:

export const mutations: MutationTree<State> = {
    ...
  // 选择图标背景
  selectColor(state: State, payload: { id: string; color: string }) {
    const list = state.todoList;
    const todo = _.find(list, payload.id);
<span class="hljs-keyword">if</span> (todo) {
  todo.color = payload.color;
}

},
// 选择图标
selectIcon(state: State, payload: { id: string; icon: string }) {
const list = state.todoList;
const todo = _.find(list, payload.id);
if (todo) {
todo.iconName = payload.icon;
}
},

// 编辑任务名称
changeName(state: State, payload: { id: string; value: string }) {
const list = state.todoList;
const todo = _.find(list, payload.id);
if (todo) {
todo.name = payload.value;
}
}
};

后面我们借助 vuex-class 把它们作为类的成员使用,我们看 src/views/Create.vue 的部分:

export default class Create extends Vue {
  private iconSetting: string[] = config.iconSetting;
  private colorSetting: string[] = config.colorSetting;
  private id!: string;
  private index!: number;
  private currentItem!: ITodoItem;
  @Mutation
  private selectColor!: (payload: { id: string; color: string }) => void;
  @Mutation
  private selectIcon!: (payload: { id: string; icon: string }) => void;
  @Mutation
  private changeName!: (payload: { id: string; value: string }) => void;
  @Getter private getCurrentTodoList!: ITodoItem[];
  // 获取当前将要创建的todo的id
  private mounted() {
    console.log(this.getCurrentTodoList);
    const list = this.getCurrentTodoList;
    this.index = list.length - 1;
    const currentItem = list[this.index];
    this.id = currentItem.id;
  }
  // 计算当前icon名称
  private get iconComputed() {
    const currentItem = _.find(this.getCurrentTodoList, this.id);
    const { iconName } = currentItem!;
    return iconName;
  }
  // 计算当前背景颜色
  private get colorComputed() {
    const currentItem = _.find(this.getCurrentTodoList, this.id);
    const { color } = currentItem!;
    return color;
  }
  private changeColorHandle(color: string) {
    this.selectColor({ id: this.id, color });
  }
  private handleIconHandle(name: string) {
    this.selectIcon({ id: this.id, icon: name });
  }
  private get nameComputed() {
    const todo = _.find(this.getCurrentTodoList, this.id);
    return todo!.name;
  }
  private set nameComputed(name) {
    this.changeName({ id: this.id, value: name });
  }
}

你可能会好奇 @Getter 是干什么的,这个其实就是将 Vuex 中的 Getter 添加到类成员的装饰器,我们在这里把 todoList 这个数组作引入进来,方便操作。

删除、完成 todo 任务

我们创建完任务之后回到首页,会发现多出了一个 todo 任务,这个时候我们需要两个逻辑:

  • 任务完成逻辑
  • 删除任务逻辑

我们在 mutations 中编辑相关逻辑:

  deleteTodoItem(state: State, id: string) {
    const list: ITodoItem[] = state.todoList;
    state.todoList = list.filter(item => item.id !== id);
  }
  // 将此任务设置为完成
  doneTodoItem(state: State, id: string) {
    const list: ITodoItem[] = state.todoList;
    const todo = _.find(list, id);
    if (todo) {
      todo.isDone = true;
    }
  }

然后我们在 src/views/Home.vue 部分应用:

export default class Home extends Vue {
  @Mutation private deleteTodoItem!: (id: string) => void;
  @Mutation private doneTodoItem!: (id: string) => void;
  @Getter private getCurrentTodoList!: ITodoItem[];

private get TodoListComputed() {
const list = this.getCurrentTodoList.filter(
item => item.mode !== Mode.edit
);

<span class="hljs-keyword">return</span> list;

}

private delHandle(id: string) {
this.deleteTodoItem(id);
}

private doneHandle(id: string) {
this.doneTodoItem(id);
}
}

小结

逻辑编写部分没有什么有太大难度的东西,强烈建议你把源代码拷贝下来,结合本节内容和注释进行学习,因为其中涉及了一些细节我们碍于篇幅没办法都涉及到。

这就是我们借助 TypeScript + Vue 完成的一个简单的 TODO 应用,其实如果你搞清楚了这个小应用,整个使用就不会有太大问题了。

但是值得注意的是,目前 vue2.6x 虽然对 TypeScript 的支持已经有了一定进步,但是整体的代码提示还是不到位,语法噪音依然非常大,vue 3.0 要到 2020年一季度发布,这个版本的 Vue 只是个过渡,在下个用 TypeScript 重写后的 Vue 3.0 发布后我们会继续进行实战。

@hello-chinese hello-chinese added the typescript学习 Improvements or additions to documentation label Sep 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
typescript学习 Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

1 participant