1、什么是vuex?
vuex 是一个专为 Vue.js 应用程序开发的状态管理模式(通俗一点的说Vuex就是存储数据的工具,类似于cookie、sessionStorage、localStorage)。
2、vuex和cookie、sessionStorage、localStorage的区别:
cookie、sessionStorage、localStorage是浏览器存储,每当页面刷新时数据依然存在(在过期时间内),而vuex在页面刷新时存储的数据会丢失。
3、vuex一般用于大型的SPA应用,否则最好不要使用vuex。
4、基本用法:
npm安装: npm install vuex --save
新建一个store文件夹,在该文件夹下新建一个index.js文件,机构目录入下图:
Vuex有以下几个选项:state、mutations、actions、getters、module
在该index.js文件里:
import Vue from 'vue'; //引入vue import Vuex from 'vuex';//引入vuex Vue.use(Vuex);
//新建一个store仓库, state 是存储数据的 const store=new Vuex.Store({ state:{ count:12 } }) export default store;
4.1、读取数据: 在任何组件里可以通过$store.state.count来读取数据
<p>{{$store.state.count}}</p>
或者通过计算属性进行处理
<template> <div class="hello"> <!--直接读取--> <p>{{$store.state.count}}</p> <!--通过计算属性获取--> <p>{{count}}</p> </div> </template> <script> export default { data(){ return{ originData:'hello Vue' } }, computed:{ count(){ return this.$store.state.count; } } } </script> <style> </style>
结果如下图:
4.2、修改数据:
在组件内,来自store的数据只能读取,不能手动修改,改变store中数据的唯一途径就是显式的提交mutations。
在以下demo中实现加1和减一的效果:
const store=new Vuex.Store({ //选项一:state用来存储数据的 state:{ count:12 }, //选项二:mutations用来修改state中的数据的 mutations:{ increament(state){ console.log(state); //以上打印的是 count:12 ,在这里可以获取到state中的count数据,所以可以在这里直接进行修改 state.count ++; }, decrease(state){
console.log(state); state.count --; } } })
加1的结果:
减1的结果:
以上结果显式通过mutations已经成功的修改了state中的数据。
此外mutations还可以接受第二个参数:
修改之前的代码:
methods:{
//自定义一个num传给mutations addOne(){ let num=10; this.$store.commit('increament',num); }, reduceOne(){ let num=5; this.$store.commit('decrease',num); } }
mutations:{ increament(state,num){ console.log(num); //打印的是10 state.count+=num; }, decrease(state,num){ console.log(num); //打印的是5 state.count-=num; } }
此时,加10和减5修改成功。
5、高级用法:
Vuex除了state、mutations外还有getters、actions、modules选项
5.1、getters:
“Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算”
demo:过滤出偶数
const store=new Vuex.Store({ //选项一:state用来存储数据的 state:{ count:[1,2,3,4,5,6,7,8,9,10] }, //选项二:mutations用来修改state中的数据的 mutations:{ increament(state,num){ state.count+=num; }, decrease(state,num){ state.count-=num; } }, //选项三:getters相当于计算属性 getters:{ filterData(state){ console.log(state) //过滤出偶数 return state.count.filter(item=>item%2==0) } } })
<template> <div class="hello"> <!--通过计算属性获取--> <p v-for="item in count">{{item}}</p> </div> </template> <script> export default { data(){ return{ originData:'hello Vue' } }, computed:{ count(){ return this.$store.getters.filterData; } } } </script> <style> </style>
结果如下:
5.2、actions:异步操作state数据,一般用于后台请求数据。
mutation里尽量不要异步操作数据,如果异步操作数据了,组件在commit后数据不能立即改变,而且也不知道什么会改变,actions就是专门处理异步操作的。
demo:3s后原数据加20
<template> <div class="hello"> 异步数据:{{count}} <button @click="asyncClick">异步处理</button> </div> </template> <script> export default { data(){ return{ originData:'hello Vue' } }, computed:{ list(){ return this.$store.getters.filterData; }, count(){ return this.$store.state.count; } }, methods:{ asyncClick(){ //这里随便传过去一个数字20 this.$store.dispatch('asyncIncreament',20).then(()=>{ //修改成功的回调 console.log(this.$store.state.count); //32 }); } } } </script> <style> </style>
store
const store=new Vuex.Store({ //选项一:state用来存储数据的 state:{ list:[1,2,3,4,5,6,7,8,9,10], count:12, }, //选项二:mutations用来修改state中的数据的 mutations:{ increament(state,num){ state.count+=num; }, decrease(state,num){ state.count-=num; } }, //选项三:getters相当于计算属性 getters:{ filterData(state){ console.log(state) //过滤出偶数 return state.list.filter(item=>item%2==0) } }, //选项四:actions实现异步操作 actions:{ asyncIncreament(content,num){ return new Promise(resolve=>{ setTimeout(()=>{ content.commit('increament',num); resolve(); },3000) }) } } }) export default store;
结果如下:
点击 “异步处理”按钮3s后页面的数据由原来的12变为32,修改成功后控制台打印结果32
5.3、module: 模块化处理
module是用来将store分割到不同的模块,当你的项目足够大时,store里的state、getters、mutations、actions会非常多,都放在mian.js里不是很友好,使用modules可以把它们写到不同的文件中。每个module拥有自己的state、getters、mutations、 actions,而且可以多层嵌套。
demo:
目录结构:
<template> <div class="hello"> <button @click="asyncClick">异步处理</button> <p> 模块A的数据:{{countOne}}</p> <p> 模块B的数据:{{countTwo}}</p> </div> </template> <script> export default { data(){ return{ originData:'hello Vue' } }, computed:{ countOne(){ //获取模块a的state数据 return this.$store.state.a.countOne; }, countTwo(){ //获取模块b的state数据 return this.$store.state.b.countTwo; } }, methods:{ asyncClick(){ //异步处理模块a的数据 this.$store.dispatch('asyncIncreamenta',30); //异步处理模块b的数据 this.$store.dispatch('asyncIncreamentb',30); } } } </script>
模块a:
//模块A export default{ //选项一:state用来存储数据的 state:{ list:[1,2,3,4,5,6,7,8,9,10], countOne:12, }, //选项二:mutations用来修改state中的数据的 mutations:{ increamentOne(state,num){ state.countOne+=num; }, decreaseOne(state,num){ state.countOne-=num; } }, //选项三:getters相当于计算属性 getters:{ filterDataOne(countOne){ //过滤出偶数 return countOne.list.filter(item=>item%2==0) } }, //选项四:actions实现异步操作 actions:{ asyncIncreamenta(content,num){ return new Promise(resolve=>{ setTimeout(()=>{ content.commit('increamentOne',num); resolve(); },1000) }) } } }
模块b:
//模块B export default{ //选项一:state用来存储数据的 state:{ list:[1,2,3,4,5,6,7,8,9,10], countTwo:52, }, //选项二:mutations用来修改state中的数据的 mutations:{ increament(state,num){ state.countTwo+=num; }, decrease(state,num){ state.count-=num; } }, //选项三:getters相当于计算属性 getters:{ filterData(state){ //过滤出偶数 return state.list.filter(item=>item%2==0) } }, //选项四:actions实现异步操作 actions:{ asyncIncreamentb(content,num){ return new Promise(resolve=>{ setTimeout(()=>{ content.commit('increament',num); resolve(); },1000) }) } } }
store下的index.js:
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); import moduleA from './moduleA.js' import moduleB from './moduleB.js' const store=new Vuex.Store({ modules:{ a:moduleA, b:moduleB } }) export default store;
点击“异步处理”按钮 1s后模块a和模块b的state的数据发生了改变。
6、mapState
、mapGetters、mapActions:
6.1、mapState
通过this.$store.state.count 获取store中的数据写法很长,所以为了简化写法可以使用mapState
进行操作,
<template> <div class="hello"> <button @click="asyncClick">异步处理</button> <p> 模块A的数据:{{countOne}}</p> <p> 模块B的数据:{{countTwo}}</p> <p> mapState获取模块A的数据:{{messageOne}}</p> <p> mapState获取模块B的数据:{{messageTwo}}</p> </div> </template> <script> //首先引入mapState,mapGetters,mapActions import {mapState,mapGetters,mapActions} from 'vuex' export default { data(){ return{ originData:'hello Vue' } }, computed:{ countOne(){ //获取模块a的state数据 return this.$store.state.a.countOne; }, countTwo(){ //获取模块b的state数据 return this.$store.state.b.countTwo; }, //这里的3个点表示扩展运算符(ES6的知识) ...mapState({ messageOne: state => state.a.countOne, /* 相当于: messageOne(){ return state.a.countOne; } * */ messageTwo: state => state.b.countTwo, }) }, methods:{ asyncClick(){ //异步处理模块a的数据 this.$store.dispatch('asyncIncreamenta',30); //异步处理模块b的数据 this.$store.dispatch('asyncIncreamentb',30); } } } </script> <style> </style>
结果如下:
结果显示:通过mapState获取的数据和通过this.$store获取的数据一致。
6.2、mapGetters
<template> <div class="hello"> <button @click="asyncClick">异步处理</button> <p> 模块A的数据:{{countOne}}</p> <p> 模块B的数据:{{countTwo}}</p> <!--遍历模块a中的列表--> <p>遍历模块a中的列表:</p> <p v-for="item in filterDataOne">{{item}}</p> </div> </template> <script> //首先引入mapState,mapGetters,mapActions import {mapState,mapGetters,mapActions} from 'vuex' export default { data(){ return{ originData:'hello Vue' } }, computed:{ countOne(){ //获取模块a的state数据 return this.$store.state.a.countOne; }, countTwo(){ //获取模块b的state数据 return this.$store.state.b.countTwo; }, ...mapGetters([ //模块a中 filterDataOne 'filterDataOne', ]), }, methods:{ asyncClick(){ //异步处理模块a的数据 this.$store.dispatch('asyncIncreamenta',30); //异步处理模块b的数据 this.$store.dispatch('asyncIncreamentb',30); } } } </script>
结果如下:
6.3、mapAction:
<template> <div class="hello"> <!-- <button @click="asyncClick">异步处理</button>--> <p> 模块A的数据:{{countOne}}</p> <p> 模块B的数据:{{countTwo}}</p> <p> mapState获取模块A的数据:{{messageOne}}</p> <p> mapState获取模块B的数据:{{messageTwo}}</p> <!--遍历模块a中的列表--> <!--<p v-for="item in filterDataOne">{{item}}</p>--> <button @click="asyncIncreamenta(100)">mapActions异步处理</button> </div> </template> <script> //首先引入mapState,mapGetters,mapActions import {mapState,mapGetters,mapActions} from 'vuex' export default { data(){ return{ originData:'hello Vue' } }, computed:{ countOne(){ //获取模块a的state数据 return this.$store.state.a.countOne; }, countTwo(){ //获取模块b的state数据 return this.$store.state.b.countTwo; }, //这里的3个点表示扩展运算符(ES6的知识) ...mapState({ messageOne: state => state.a.countOne, /* 相当于: messageOne(){ return state.a.countOne; } * */ messageTwo: state => state.b.countTwo, }), ...mapGetters([ //模块a中 filterDataOne 'filterDataOne', ]), }, methods:{ ...mapActions(['asyncIncreamenta']), // asyncClick(){ // //异步处理模块a的数据 // this.$store.dispatch('asyncIncreamenta',30); // //异步处理模块b的数据 // this.$store.dispatch('asyncIncreamentb',30); // } } } </script> <style> </style>
点击“mapActions”按钮1后结果如下:
模块a的数据增加了100