Post

Vuex 的五个核心模块的作用

Vuex 的五个核心模块的作用

Vuex 的核心模块分别是:

  1. state(状态) - Vuex 的数据存储中心,存放所有共享的应用状态(类似组件的 data)。
  2. getters(派生状态) - 允许我们基于 state 计算派生出新的数据(类似 computed)。
  3. mutations(同步更改状态) - 只能通过 mutation 修改 state,且必须是同步的。
  4. actions(异步逻辑) - 提供执行异步操作的方法,最终调用 mutations 更新 state
  5. modules(模块化) - 允许将 Vuex store 拆分成多个独立的子模块,以便管理大型项目。

Vuex 的五个模块如何协作?

它们的协作流程如下:

  1. 组件从 store 读取 state,并通过 getters 计算派生数据。
  2. 组件调用 dispatch(action) 触发 actions,执行异步操作(如 API 请求)。
  3. actions 内部调用 commit(mutation),触发 mutations,修改 state
  4. state 发生变化后,Vue 组件会自动更新视图。

案例:Todo List

(1) 安装 Vuex

1
npm install vue vuex --save

(2) 创建 Vuex Store

我们创建一个 store.js 文件,使用 Vuex 管理 Todo List 的状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    todos: [] // 任务列表
  },

  getters: {
    // 计算未完成的任务数量
    remainingTodos: state => state.todos.filter(todo => !todo.completed).length
  },

  mutations: {
    // 添加任务
    ADD_TODO(state, task) {
      state.todos.push({ id: Date.now(), task, completed: false });
    },
    // 切换任务状态
    TOGGLE_TODO(state, todoId) {
      const todo = state.todos.find(todo => todo.id === todoId);
      if (todo) {
        todo.completed = !todo.completed;
      }
    },
    // 设置任务列表(用于异步获取数据)
    SET_TODOS(state, todos) {
      state.todos = todos;
    }
  },

  actions: {
    // 异步加载任务(模拟 API 请求)
    fetchTodos({ commit }) {
      setTimeout(() => {
        const sampleTodos = [
          { id: 1, task: '学习 Vuex', completed: false },
          { id: 2, task: '完成 Vue 项目', completed: false },
          { id: 3, task: '阅读 Vue 2 文档', completed: true }
        ];
        commit('SET_TODOS', sampleTodos);
      }, 1000);
    }
  },

  modules: {
    // 这里可以拆分模块,但本例不使用
  }
});

在 Vue 组件中使用 Vuex

我们在 TodoList.vue 组件中使用 Vuex 来管理任务列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<template>
  <div>
    <h1>Vuex Todo List</h1>
    
    <!-- 输入框和添加任务按钮 -->
    <input v-model="newTask" @keyup.enter="addTodo" placeholder="输入任务..." />
    <button @click="addTodo">添加任务</button>

    <!-- 任务列表 -->
    <ul>
      <li v-for="todo in todos" :key="todo.id">
        <input type="checkbox" :checked="todo.completed" @change="toggleTodo(todo.id)">
        <span :class="{ completed: todo.completed }"></span>
      </li>
    </ul>

    <!-- 任务统计 -->
    <p>剩余未完成任务数: </p>

    <!-- 加载任务按钮 -->
    <button @click="fetchTodos">加载任务</button>
  </div>
</template>

<script>
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';

export default {
  data() {
    return {
      newTask: ''
    };
  },
  
  computed: {
    ...mapState(['todos']),  // 映射 state
    ...mapGetters(['remainingTodos']) // 映射 getters
  },

  methods: {
    ...mapMutations(['ADD_TODO', 'TOGGLE_TODO']), // 映射 mutations
    ...mapActions(['fetchTodos']), // 映射 actions

    addTodo() {
      if (this.newTask.trim()) {
        this.ADD_TODO(this.newTask);
        this.newTask = '';
      }
    },

    toggleTodo(todoId) {
      this.TOGGLE_TODO(todoId);
    }
  }
};
</script>

<style scoped>
.completed {
  text-decoration: line-through;
}
</style>
This post is licensed under CC BY 4.0 by the author.