阅读 716

vuex-stepbystep 经典案例,详细注释一步到位

系列文章

Vuex

是什么(官网已经很完善了)

  • Vuex 是一个 Vue 中的状态管理工具
  • 状态,即数据(data)
  • 状态管理工具就是用来管理 Vue 项目中组件中的数据的

为什么要使用 Vuex

  • Vuex 只应该在中大型复杂的 Vue 项目中使用
  • 小项目中不需要使用 Vuex

Vuex 的说明

  • Vuex 采用集中的方式统一管理了项目中所有需要共享的数据,只要组件之间相同共享数据就要通过 Vuex 才能实现
  • 可预测性
  • 可以简单理解为 Vuex 是一个增强版的 bus

状态管理

  • 前端最早的状态管理思想是由 React 的 Flux 提出来的
  • Flux 不仅提出了 前端状态管理的思想,也提供对应的实现
  • 其他状态管理库:Flux / Redux / Mobx / Vuex

actions 和 mutations 的区别

Vuex 中的核心概念

  • store

Vuex 的特点

  • Vuex 中的数据也是响应式的(双向绑定的)

案例搭建

  • 技术点
    • vuex
    • vue-cli 2.0
    • todos 模板
  • 项目目录

  • 然后我们开始搭建项目,使用vue-cli的步骤,就跳上过了,楼主在vue-admin教程中有详细步骤,现在我们在src目录下新建store文件夹,然后新建index.js文件,然后我们初始化store,代码如下

import Vue from 'vue'//引入vue
import Vuex from 'vuex'//引入vuex

// 安装
Vue.use(Vuex)

// 初始化state
const state = {}

// mutations
const mutations = {}

// 创建store把state和mutation 写入Vuex.store中
const store = new Vuex.Store({
  state,
  mutations
})

export default store //导出store
复制代码
  • 然后我们在main.js引入,挂载到vue的实例中
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'

// 导入样式
import '@/assets/index.css'

// 导入store
import store from './store'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  // 将 Vuex(store) 和 Vue实例关联到一起
  store,
  components: { App },
  template: '<App/>'
})

复制代码
  • 然后配置App.vue,把todos模板组件导入App.vue中,我们的store就配置好了

功能完成

  • 效果图 (ps:经典到吐)
  • 我们现在完善store,把数据填入,进行增删更新的一些状态的统一操作。
import Vue from 'vue'//引入vue
import Vuex from 'vuex'//引入vuex

// 安装
Vue.use(Vuex)

// 初始化state
const state = {
  todos: [
    { id: 1, name: '秃头', done: false },
    { id: 2, name: '女朋友跑了', done: false },
    { id: 3, name: '左手更加的有力', done: true }
  ]
}

// mutations配置
const mutations = {
  // 根据id修改完任务的成状态
  changeDone(state, payload) {
    // 1 根据id找到当前任务
    const curTodo = state.todos.find(item => item.id === payload.id) //箭头函数了解下
    // 2 状态直接取反即可
    curTodo.done = !curTodo.done
  },

  // 添加任务方法
  addTodo(state, payload) {
    const length = state.todos.length
    const id = length === 0 ? 1 : state.todos[length - 1].id + 1

    state.todos.push({
      id,
      name: payload.name,
      done: false
    })
  },

  // 删除任务方法
  delTodo(state, payload) {
    state.todos.splice(payload.index, 1)
  },

  // 更新任务方法
  updateTodo(state, payload) {
    // 查找到当前要更新的任务
    const curTodo = state.todos.find(item => item.id === payload.id)
    // 修改名称
    curTodo.name = payload.name
  },

  // 清除已完成任务
  clearAllDone(state) {
    state.todos = state.todos.filter(item => !item.done)
  }
}

// actions 异步操作(面试考察点)
// 内部还是提交的 mutations
const actions = {
  // 异步添加任务
  addTodoAsync(context, payload) {
    // setTimeout就是一个异步操作, 内部还是提交的 mutations
    setTimeout(() => {
      context.commit('addTodo', {
        name: payload.name
      })
    }, 2000)
  }
}

// getters
// 相当于Vue组件中的 计算属性 ,用法完全相同
// 当需要从现有的state中得到一些新的数据(比如:从 todos 集合中,得到未完成任务数量)
// 就要使用 getters ,也就是计算属性
const getters = {
  // 未完成任务数量
  unDoneCount(state) {
    return state.todos.filter(item => !item.done).length
  },

  // 控制清除已完成任务按钮的展示和隐藏
  showClearDone(state) {
    return state.todos.some(item => item.done)
  }
}

// 创建store
const store = new Vuex.Store({
  // 开启严格模式
  // 开发期间 NODE_ENV 的值为: 'development'
  // 生成环境中 NODE_ENV 的值为: 'production'
  strict: process.env.NODE_ENV !== 'production',
  state,
  mutations,
  actions,
  getters
})

export default store

复制代码
  • 然后我们进行TodoHeader的添加操作
<template>
  <header class="header">
    <h1>todos</h1>
    <input 
      <!--数据绑定,对应data中的数据-->
		v-model="todoName" 
		<!--enter修饰符,绑定时间-->
		@keyup.enter="addTodo"
		 class="new-todo" 
		 placeholder="What needs to be done?"
		 <!--自动聚焦-->
		 autofocus>
  </header>
</template>

<script>
export default {
  data() {
    return {
      // 因为这个数据只会在当前组件中使用
      // 因此,就不需要放到 Vuex 中
      todoName: ''
    }
  },

  methods: {
    // 添加任务
    addTodo() {
    //input输入框通常我们会trim一下,把空格干掉
      if (this.todoName.trim() === '') {
        return
      }

      // 调用 Vuex 中提供的 mutations 即可(在组件中,通过$store.commit方法来执行mutation)
      // this.$store.commit('addTodo', {
      //   name: this.todoName
      // })

      // 调用 actions 来完成,异步添加(action在组件内通过$store.dispatch触发)
      this.$store.dispatch('addTodoAsync', {
        name: this.todoName
      })

      this.todoName = ''//完成之后,清空input框的内容
    }
  }
}
</script>
复制代码
  • 然后我们操作列表组件TodoList

<template>
  <section class="main">
    <input id="toggle-all" class="toggle-all" type="checkbox">
    <label for="toggle-all">Mark all as complete</label>
    <ul class="todo-list">
      <!--
        完成状态: completed
        编辑状态: editing
       -->
      <li 
			:class="{ completed: todo.done, editing: todo.id === editId }"
			 v-for="(todo, index) in $store.state.todos" 
			 :key="todo.id">
        <div class="view">
          <!--
            前提:因为我们知道 Vuex 中的数据,只能通过 mutations 中提供的方法来修改
            因为在 checkbox 中使用了 v-model,v-model是双向绑定的,当点击 复选框 的时候,会将其对应的数据修改,
            这样就违背了 Vuex 中数据只能由 mutations 修改这个原则了!!!

            数据 -> 视图: :checked="todo.done" (单向)
            视图 -> 数据: 先绑定一个事件,在事件中调用 mutations 来完成数据修改
           -->
          <input 
					class="toggle"
					 type="checkbox"
					 :checked="todo.done"
					 @change="changeDone(todo.id)">
          <!-- <input class="toggle" type="checkbox" v-model="todo.done"> -->
          <label @dblclick="showEditStatus(todo.id)">{{ todo.name }}</label>
          <button class="destroy" @click="delTodo(index)"></button>
        </div>
        <input class="edit" :value="todo.name" @keyup.enter="updateTodo(todo.id, index)" ref="todoUpdate">
      </li>
    </ul>
  </section>
</template>

<script>
export default {
  data() {
    return {
      // 临时变量,用来处理编辑状态
      editId: -1
    }
  },
  methods: {
    // 出现编辑状态
    showEditStatus(id) {
      this.editId = id
    },

    // 更新任务名称
    updateTodo(id, index) {
      // 根据索引号找到对应的文本框
      const name = this.$refs.todoUpdate[index].value

      this.$store.commit('updateTodo', {
        id,
        name
      })

      // 去掉编辑状态
      this.editId = -1
    },

    // 切换完成状态
    changeDone(id) {
      // 调用 mutations 中提供的方法,来修改state中的数据
      this.$store.commit('changeDone', {
        id
      })
    },

    // 删除任务
    delTodo(index) {
      this.$store.commit('delTodo', {
        index
      })
    }
  }
}
</script
<style>
</style>

复制代码
  • 底部就一个清除,直接贴代码了
export default {
  methods: {
    // 清除所有已完成任务
    clearAllDone() {
      this.$store.commit('clearAllDone')
    }
  }
}
复制代码

结语

  • 我看了有些,博文,感觉把vueX都神话了,各位小伙伴把我这篇教程看完,其实就这些东西。
  • 大项目确实很方便,具体使用:按需使用。
关注下面的标签,发现更多相似文章
评论