Vuex基础
一、初始化项目
1、项目创建
vue create 项目名 //示例: vue craete hm-hr
2、添加 vuex 功能
npm i vuex 或 yarn add vuex
3、引入、使用、创建仓库实例和挂载仓库实例到根实例当中 vuex
import Vuex from "vuex" //引入 Vue.use(Vuex) //使用 const store = new Vuex.Store() //创建仓库实例 new Vue({ //挂载到根实例中 store, render: h => h(App), }).$mount('#app')
4、检验是否安装引入成功
在app.vue中 created(){ //安装完vuex 会在组件中注入 一个 $store变量 console.log(this.$store); }
二、Vuex基础
0、vuex的基本概念
vuex是采用集中式管理组件依赖的共享数据的一个工具,可以解决不同组件数据共享问题。 • Vuex 是一个专为 Vue.js 应用程序开发的**状态管理模式**。它采用**`集中式`**存储管理应用的所有组件的状态,并以相应的规则保证状态以一种**`可预测`**的方式发生变化。
-
结论
1. 修改state状态必须通过**`mutations`** 2. **`mutations`**只能执行同步代码,类似ajax,定时器之类的异步代码不能在mutations中执行 3. 执行异步代码,要通过actions,然后将数据提交给mutations才可以完成 4. state的状态即共享数据可以在组件中引用 5. 组件中可以调用action
1、state (共享状态数据)
-
基本概念
state是放置所有公共状态的属性,如果你有一个公共状态数据 , 你只需要定义在 state对象中
-
基本创建
//创建仓库实例 const store = new Vuex.Store( // 数据存储在对象里面 { state: { count: 0, name: "tom" //这两个都是保存的数据 } } )
-
基本使用
<template> <div> 测试 <!-- 基本使用,插值表达式 --> //1、 可以直接插值表达式 <div>{{$store.state.count}}</div> // 0 <div>{{$store.state.name}}</div> // tom //2、也可以在data中声明变量 {{name}} // tom </div> </template> export default { data(){ return{ name:this.$store.state.name } }, created(){ //安装完vuex 会在组件中注入 一个 $store变量 console.log(this.$store); console.log(this.$store.state.name); //tom } }
-
优化(计算属性)
<div> <div>{{name}}</div> <div>{{count}}</div> </div> //在计算属性中使用 // 能跟踪后续的更改 // 都是函数 记得加 return computed:{ name(){ return this.$store.state.name } , count(){ return this.$store.state.count } }
-
辅助函数(mapState)
import {mapState} from "vuex" // 辅助函数1、引入mapState computed:{ //辅助函数2、采用数组形式引入state属性 ...mapState(["name","count"]) }
2、mutations(同步修改state)(方法)
-
基本概念
mutations是一个对象,对象中存放修改state的方法 ,只能执行同步代码,目的是形成数据快照
数据快照
:一次mutation的执行,立刻得到一种视图状态,因为是立刻,所以必须是同步
-
准备严格模式
//创建仓库实例 const store = new Vuex.Store( // 数据存储在对象里 { strict:true, //限制state 只能被mutaitions 修改的严格模式 state: { count: 0, name: "tom" } } )
-
基本创建
/创建仓库实例 const store = new Vuex.Store( // 数据存储在对象里 { //限制state 只能被mutations 修改的严格模式 strict: true, state: { count: 0, name: "tom" }, mutations: { //对象里面是方法 // 方法里面的参数: //第一个参数是当前store的state属性 //payload 载荷 是运输参数 调用 mutations的时候可以传递参数 传递载荷 setCount(state, data) { state.count += data } } } )
-
基本使用($store.commit)
<button @click="$store.commit('setCount',666)">点我+666</button> //效果 : 点击按钮 count + 传过来的参数 666
-
优化
在main.js中的仓库对象里面 mutations: { //对象里面是方法 // 方法里面的参数: //第一个参数是当前store的state属性 //payload 载荷 是运输参数 调用 mutations的时候可以传递参数 传递载荷 setCount(state, data) { state.count += data } } App.js中 的methods 里 <button @click="setCount(999)">点我+999</button> //与data同级 methods:{ setCount(data) { this.$store.commit("setCount",data) } }
-
辅助函数(mapMutations)
//引入辅助函数 mapMutations import {mapState,mapMutations} from "vuex" //2在methods 里面写 methods:{ // setCount(data) { // this.$store.commit("setCount",data) // } ...mapMutations(["setCount"]) //采用数组形式引入state属性 }
但是请注意: Vuex中mutations中要求不能写异步代码,如果有异步的ajax请求,应该放置在actions中
3、actions(异步修改state)(方法)
-
基本概念
actions 是一个对象对象中存放着方法,state是存放数据的,mutations是同步更新数据,actions则负责进行异步操作
-
基本创建
//异步都要放在actions中 在store对象里面与mutatoins对象同级哦 actions: { asynSetCount(store,data) { //默认得到当前的仓库是例 store //用延时器做异步演示 setTimeout(() => { //actions 不能直接修改 state 需要通过 mutations store.commit("setCount",data) },1000) } }
-
基本使用
<button @click="$store.dispatch('asynSetCount',666)">点我增加延迟666</button>
-
优化
<button @click="asynSetCount(666)">点我延迟666</button> methods:{ asynSetCount(data){ this.$store.dispatch("asynSetCount",data) } }
-
辅助函数(mapActions)
import {mapState,mapMutations,mapActions} from "vuex" // 辅助函数1、引入mapActions methods:{ // setCount(data) { // this.$store.commit("setCount",data) // } ...mapMutations(["setCount"]), // asynSetCount(data){ // this.$store.dispatch("asynSetCount",data) // } //等价于上面 ...mapActions(["asynSetCount"]) //采用数组形式引入state属性 }
4、getters(每个属性都是函数)
-
基本创建
const store = new Vuex.Store( // 数据存储在对象里 { //限制state 只能被mutations 修改的严格模式 strict: true, state: { count: 0, name: "tom", list: [1, 2, 3, 4, 5, 6, 7, 888, 77, 666] }, ...... getters: { //这里是依赖于state 的派生数据 // 每个属性都是函数(所以记得加return),默认可以得到state对象 // 返回值就是最终显示的数据 必须要有返回值 //如果需要的是显示 list ,当比5大的数据 演示 filterList(state) { return state.list.filter(val => val > 5) //返回处理过后的数据 } } }
-
基本使用
-
<div>{{$store.state.list}}</div> /[ 1, 2, 3, 4, 5, 6, 7, 888, 77, 666 ] <div>{{$store.getters.filterList}}</div> // [ 6, 7, 888, 77, 666 ]
-
优化
<div>{{filterList}}</div> // 总结 :因为getters里面的每个属性都是函数,所以需要写在计算属性里面,而mutations 和actions 里面存放的是修改state 数据的方法所以写在methods 里面 computed:{ filterList(){ //计算属性里面的函数记得加上return return this.$store.getters.filterList } }
-
辅助函数(mapGetters)
computed:{ //等价于下面 ...mapGetters(["filterList"]) //采用数组形式引入state属性 // filterList(){ // return this.$store.getters.filterList // }, } }
-
在项目中的常见用法
很少会有复杂的逻辑,通常都是用来进行state嵌套数据的简化获取 main.js中
//创建仓库实例 记得数据是存到 state里面的哦 const store = new Vuex.Store( // 数据存储在对象里 { //限制state 只能被mutations 修改的严格模式 strict: true, state: { count: 0, name: "tom", list: [1, 2, 3, 4, 5, 6, 7, 888, 77, 666], students: { name: "翠花", age: 18, school: { name: "吉山幼儿园", address: "珠吉路58号" } }, },
getters: { //这里是依赖于state 的派生数据 // 每个属性都是函数,默认可以得到state对象 // 返回值就是最终显示的数据 //如果需要的是显示 list ,当比5大的数据 演示 // filterList(state) { // return state.list.filter(val => val > 5) // } //简写模式 filterList: state => state.list.filter(val=>val>5), schoolAddress: state=>state.students.school.address }
//App.vue中 <div>{{$store.getters.schoolAddress}}</div>
5、modules(模块化)
-
基本概念
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象 state 当中。当应用变得非常复杂时,就有可能变得相当臃肿。Vuex会变得越来越难以维护, 由此,又有了Vuex的模块化
-
基本创建
//创建仓库实例 const store = new Vuex.Store( // 数据存储在对象里 { //限制state 只能被mutations 修改的严格模式 strict: true, //本来这里直接放state、mutations、actions //如果分模块就应该放在 modules里面 modules: { //假设有 user 和 setting 模块 user: { state: { name:"狗蛋" } }, setting: { state: { token:"666" } } } }
-
基本使用
1.模块化中的state
由于经过 vuex 的封装和转换, 真实获取数据时, 跟创建 Modules 的写法有所出
<!-- 模块化状态下,state的固定获取方法:$store.state 模块名.属性名 --> 用户名称: <div>{{$store.state.user.name}}</div><br> 用户token: <div>{{$store.state.setting.token}}</div>
2.模块化中的mutations和actions
默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应
但是,如果我们想保证内部模块的高封闭性,我们可以采用namespaced来进行区分
-
添加空间命名锁 避免全局通用mutations
modules: { //假设有 user 和 setting 模块 user: { //添加命名空间锁,避免全局通用mutations namespaced:true, state: { name: "狗蛋" }, mutations: { getName(state) { state.name= "翠花" } } }, setting: { state: { token: "666" } } }
在AAp.vue中调用mutations方法会报错
<button @click="$store.commit('getName')">点我变翠花</button> // [vuex] unknown mutation type: getName 报错信息
(1).基于命名空间锁的mutations的调用方法1
直接在调用时加上模块路径即可
<!-- 调用带有命名空间锁的函数 最简单的方法就是添加模块路径 --> <button @click="$store.commit('user/getName')">点我变翠花</button> //效果: 狗蛋变翠花
(2)基于命名空间锁的mutations的调用方法2
在使用全局的辅助函数时, 可以指定命名空间
注意, 给出参数的顺序是 mapMutations(模块名, [函数名])
<button @click="getName">点我变翠花</button> import {mapMutations}from "vuex" export default { methods:{ //如果加了命名空间锁,直接用辅助函数生成是行不通的, //可以在传数组之前,加上一个字符串作为模块名 ...mapMutations("user",['getName']) } } // 效果 : 狗蛋变翠花
(3)基于命名空间锁的mutations的调用方法3
<button @click="getName">点我变翠花</button> //如果添加了命名空间锁还可以调用 vuex 提供的方法 //创建专门属于某个模块的辅助函数 import {createNamespacedHelpers} from "vuex" //调用这个函数时,加上模块名作为参数,就可以创建出基于该模块的辅助函数 const {mapMutations} =createNamespacedHelpers('user') export default { methods:{ ...mapMutations(["getName"]) } } //效果也是 点击按钮 狗蛋变翠花
2.1.拓展如果解构时变量名被占用的重命名方法
<button @click="getName">点我变翠花</button> <script> import {mapMutations}from "vuex" //如果添加了命名空间锁还可以调用 vuex 提供的方法 //创建专门属于某个模块的辅助函数 import {createNamespacedHelpers} from "vuex" //调用这个函数时,加上模块名作为参数,就可以创建出基于该模块的辅助函数 //假设解构的变量名已经存在,可以声明解构之后要重命名的名称 //只需要在解构时使用以下语法 const {旧变量名:新变量名} const {mapMutations:usermapMutations} =createNamespacedHelpers('user') export default { methods:{ // //如果加了命名空间锁,直接用辅助函数生成是行不通的, // //可以在传数组之前,加上一个字符串作为模块名 ...mapMutations("user",['getName']), ...usermapMutations(["getName"]) } }
3.模块中的getters
一般来说, 在模块状态下, getters 依旧是放在最外层
作用就是简化各个子模块重要数据的获取步骤
请注意,这个getters是根级别下的getters
-
创建
{ //限制state 只能被mutations 修改的严格模式 strict: true, //本来这里直接放state、mutations、actions //如果分模块就应该放在 modules里面 modules: { //假设有 user 和 setting 模块 user: { //添加命名空间锁,避免全局通用mutations namespaced:true, state: { name: "狗蛋" }, mutations: { getName(state) { state.name= "翠花" } } }, setting: { state: { token: "666" } } }, //分模块的情况下,getters还是放在最外层 //因为在这里可以直接获取到所有子模块的数据 //方便数据的简化 getters: { name: state => state.user.name, token:state=>state.setting.token } }
-
使用
用户名称: <div> {{$store.getters.name}} </div><br> 用户token: <div> {{$store.getters.token}} </div>