Vuex的介绍? ? ? ??
????????vue单页面应用中,每个组件内部的数据在data中存放,供组件内部使用,但是vue组件之间的数据共享则需要使用props传值,事件总线传值,路由跳转传值等,这样数据传递复杂,容易出错,浪费内存,在大型项目中,使用vuex进行数据共享
vuex的作用
- 能够保存全局数据,供整个应用使用
- 保存的数据是响应式
- 保存的数据可以跟踪状态的变化
vuex的核心概念以及配置项
vuex.store对象里的配置项:
- state:数据仓库,存储所有的共享数据,相当于vue组件中的data
- getters:在state的基础上派生的数据,相当于vue组件的computed
- mutations:修改state数据时,用mutation,可以跟踪状态,只能是同步代码
- actions:解决mutation只能是同步代码的问题,可以有异步
- modules:模块化
vuex的安装使用
????????npm i vuex -save
创建对象
在src/store/index.js中
import Vue ?from 'vue' import Vuex from 'vuex' Vue.use(Vuex)
export default new Vuex.Store({ ? ? state:{ ? ? ? ? ? id: '01' ? ? }, ? ? getters:{}, ? ? mutations:{}, ? ? actions:{} })
把VueX.store对象植入到vue的根属性?
在main.js中
import store from './store'
new Vue({ ? ?? ?el: '#app', ? ?? ?store,//把store对象植入到vue的根属性,在vue组件里就可以使用 this.$store拿到vueX.store对象 })
?组件里获取数据
this.$store.state.id = '02'? 这个方式虽然可以修改数据,但它不能跟踪状态。(必须)使用mutation来修改数据。
配置项详解
state
????????数据仓库,存储所有的共享数据,相当于vue组件中的data
使用:
export default new VueX.Store({ ? ? state:{ ? ? ? ? age:12, ? ? ? ? isAllowMarry:false ? ? } });
组件中
{{$store.state.age}} {{$store.state.isAllowMarry?"可以结婚了":"不要着急"}}
getters
????????在state基础上派生的数据,相当于vue组件里的computed
使用:
export default new vueX.Store({ ? ? state:{ ? ? ? ? age:12, ? ? ? ? isAdult:false ? ? }, ? ? getters:{ ? ? ? ? isAdult:function(state){ ? ? ? ? ? ? return state.isAdult?"已成年":"未成年" ? ? ? ? } ? ? },
组件里使用(实参不需要自己传,vuex已经做好了)
?{{$store.getters.isAdult}}
mutations
????????修改state数据时,用mutation,可以跟踪数据的状态,也会在vue的dev-tools工具中看到跟踪状态的效果, ????????ps:每次触发提交都会在vue-tools中记录,如果其中存在异步代码,则会先出现先记录,后响应改变数据,违背原则
使用:
?mutations:{ ? ? ? ? addAge(state){ ? ? ? ? ? ? if(state.age>=150){ ? ? ? ? ? ? ? ? state.age=150; ? ? ? ? ? ? ? ? return ; ? ? ? ? ? ? } ? ? ? ? ? ? state.age++; ? ? ? ? ? ? // 跟age状态有关的数据都同步跟着变化 ? ? ? ? ? ? if(state.age>=18){ ? ? ? ? ? ? ? ? state.isAdult = true; ? ? ? ? ? ? }else{ ? ? ? ? ? ? ? ? state.isAdult = false; ? ? ? ? ? ? }
? ? ? ? } ? ? },
组件里
?this.$store.commit(addAge);
actions
????????解决mutation里只能有同步代码的问题,action可以有异步代码,通常在actions中处理异步操作,响应结果回来后修改stata数据,在actions异步请求的回调函数中进行mutations的提交
? mutations:{ ? ? ? ? mAddAge(state,inc){ ? ? ? ? ? ? if(state.age>=150){ ? ? ? ? ? ? ? ? state.age=150; ? ? ? ? ? ? ? ? return; ? ? ? ? ? ? } ? ? ? ? ? ? state.age+=inc; ? ? ? ? ? ? if(state.age>=18){ ? ? ? ? ? ? ? ? state.isAdult = true; ? ? ? ? ? ? }else{ ? ? ? ? ? ? ? ? state.isAdult = false; ? ? ? ? ? ? } ? ? ? ? } ? ? }, ? ?? ? ? actions:{ ? ? ? ? // 参数:context就是 store对象 ? ? ? ? aAddAge(context){ ? ? ? ? ? ? axios({ ? ? ? ? ? ? ? ? url:"/inc" ? ? ? ? ? ? }).then(res=>{ ? ? ? ? ? ? ? ? // 提交mutation ? ? ? ? ? ? ? ? context.commit("mAddAge",res.data.count); ? ? ? ? ? ? }) ? ? ? ? } ? ? }
组件里
this.$store.dispatch("aAddAge")
vuex的数据流转过程
组件=>actions=>mutations=>state=>组件
ps:如果没有异步请求,就不用在组件中派发actions,直接在组件中提交mutations
actions和mutation的区别
action是来提交mutation的
mutations不能有异步操作,它是用来跟踪状态的,actions可以有异步代码(定位不同)
ps:如果组件中使用异步请求,请求成功后再提交mutations修改数据,也是可以的,但是如果有多个组件都需要发同样的请求,不如在vuex的actions中进行异步操作并提交mutations,vuex本质就是数据的共享
参数使用对象
推荐在派发actions和提交mutations时,参数使用对象的方式
? mutations:{ ? ? ? ? ? ? ? ? incAge1(state,payload){ ? ? ? ? ? ? state.age+= payload.count; ? ? ? ? ? ? if(state.age>=18){ ? ? ? ? ? ? ? ? state.isAdult = "已成年" ? ? ? ? ? ? }else{ ? ? ? ? ? ? ? ? state.isAdult = "未成年" ? ? ? ? ? ? } ? ? ? ? } ? ? },
? actions:{ ? ? ? ? incAge(context,payload){ ? ? ? ? ? ? axios({ ? ? ? ? ? ? ? ? url:"/inc" ? ? ? ? ? ? }) ? ? ? ? ? ? .then(res=>{ ? ? ? ? ? ? ? ? context.commit({ ? ? ? ? ? ? ? ? ? ? type:"incAge1", //mutation的名字 ? ? ? ? ? ? ? ? ? ? count:res.data.count ? ? ? ? ? ? ? ? });
? ? ? ? ? ? }); ? ? ? ? } ? ? }
组件中派发actions
?this.$store.dispatch({ ? ? ?type:"incAge",? ? ? ? ? ? ?incAge ?是action的名字 ? ? ?username:"haha",? ? ? ?userpass:"123" ?});
用vuex实现loading加载中的样式
在vuex中
定义一个全局属性:isLoading,来控制loading的图片的显示和隐藏
?state:{ ? ? ? ? isLoading:false, } ? ? ? ?? ?mutations:{ ? ? ?changeLoading(state,payload){ ? ? ? ? ? state.isLoading = payload.isLoading ? ? ?}, }
在App.vue中
<van-loading class="loading" type="spinner" color="#1989fa"? ? ? ? v-show="$store.state.isLoading" />
? ? ? ? ?? <script>
export default { ? } </script> ?
<style scoped>
.van-loading__spinner{ ? position: fixed; ? left:0; ? top:0; ? right: 0; ? bottom: 0; ? margin:auto; }
</style>
在请求拦截器中
?注意这个文件不是一个组件,而是一个普通模块,所以不能使用$store,所以需要引入store模块
import store from "../store";
// 请求拦截器:请求的全局工作,发生在请求到达后端之前 axios.interceptors.request.use(function(config){
? ? // 处理loading (把loading显示) ? ? store.commit({ ? ? ? ? type:"changeLoading", ? ? ? ? isLoading:true ? ? });
? ? return config; });
// 响应拦截器:响应全局工作,发生,后端响应完毕。在axios响应进入到then的回调函数之前 axios.interceptors.response.use(function(res){ ? ? ? ? // 处理loading(把loading隐藏) ? ? store.commit({ ? ? ? ? type:"changeLoading", ? ? ? ? isLoading:false ? ? }); ? ? return res;
});
|