Vuex 初学笔记 / store
vue 2017-09-22 13:47:50

参考资料:

https://vuex.vuejs.org/zh-cn/mutations.html 【官方文档】

http://www.cnblogs.com/wisewrong/p/6344390.html

http://www.cnblogs.com/fayin/p/6445385.html

http://binlive.cn/details/59941d24971b027d7be1b215

 

常用命令:(mutation只能作同步,action可以作异步)

JavaScript Code复制内容到剪贴板
  1. //读取全局变量值   
  2. this.$store.state.author  
  3.   
  4. //根据mutations方法newAuthor 中进行重新赋值为123  
  5. this.$store.commit('newAuthor','123');  
  6.   
  7. //使用actions方法getCategoryData  
  8. this.$store.dispatch("getCategoryData");  

 

关于使用异步数据这一块,要在页面中写回调

JavaScript Code复制内容到剪贴板
  1. this.$store.dispatch("getCategoryData").then(response => {  
  2.       
  3.     this.$store.commit("changeCategoryData", response.data.items);  
  4.     this.categorys = response.data.items;  
  5.       
  6. }, response => {  
  7.     // error callback    
  8. })  

 

vuex分模块:

store.js:

JavaScript Code复制内容到剪贴板
  1. import Vue from 'vue'  
  2. import Vuex from 'vuex'  
  3. import axios from 'axios'  
  4. import commonModule from "./modules/commonModule";  
  5. import categoryModule from "./modules/categoryModule"  
  6.   
  7. Vue.use(Vuex)  
  8.   
  9. const store = new Vuex.Store({  
  10.     modules: {  
  11.         common: commonModule,  
  12.         category: categoryModule,  
  13.     }  
  14. })  
  15.   
  16. export default store  

 

categoryModule.js

JavaScript Code复制内容到剪贴板
  1. import axios from 'axios'    
  2.     
  3. // 首先声明一个状态 state    
  4. const state = {    
  5.         pageTitle: '课程分类'//页面标题    
  6.         provinces: {}    
  7. }    
  8.     
  9. // 更新状态    
  10. const mutations = {    
  11.     
  12.     provinces(state, payload) {    
  13.         state.provinces = payload    
  14.     }    
  15.     
  16. }    
  17.     
  18. // 然后给 actions 注册一个事件处理函数,当这个函数被触发时,将状态提交到 mutaions中处理    
  19. const actions = {    
  20.   
  21.     //rootState为根state  
  22.     getCategoryData ({ state, commit, rootState }) {  
  23.         return rootState.common.api.getCategory;  
  24.    },  
  25.     
  26. }    
  27.     
  28. // 获取状态信息    
  29. const getter = {    
  30.     showState(state) {    
  31.         console.log(state.msg)    
  32.     }    
  33. }    
  34.     
  35. export default {    
  36.     namespaced: true//重点就在这一句,命名空间    
  37.     state,    
  38.     mutations,    
  39.     actions,    
  40.     getter,    
  41. }    

 

 

使用:

JavaScript Code复制内容到剪贴板
  1. this.$store.commit('category/provinces'"123");  
  2. console.log(this.$store.state.category.provinces);  
  3.   
  4.   
  5. this.$store.dispatch("category/getCategoryData");  

 

在A模块调用B模块action或mutation:

JavaScript Code复制内容到剪贴板
  1. actions: {  
  2.   // 在这个模块中, dispatch 和 commit 也被局部化了  
  3.   // 他们可以接受 `root` 属性以访问根 dispatch 或 commit  
  4.   someAction ({ dispatch, commit, getters, rootGetters }) {  
  5.     getters.someGetter // -> 'foo/someGetter'  
  6.     rootGetters.someGetter // -> 'someGetter'  
  7.   
  8.     dispatch('someOtherAction'// -> 'foo/someOtherAction'  
  9.     dispatch('someOtherAction'null, { root: true }) // -> 'someOtherAction'  
  10.   
  11.     commit('someMutation'// -> 'foo/someMutation'  
  12.     commit('someMutation'null, { root: true }) // -> 'someMutation'  
  13.   },  
  14.   someOtherAction (ctx, payload) { ... }  
  15. }  

 

如果在页面中绑定了数据,但数据在vuex模块中是异步请求过来的 ,数据渲染就不能再用data来赋值,原因如下:

data是有缓存的,一旦Vuex中值改变了,没法做到响应。
而放在computed中,虽然也有缓存,但会自动监视依赖。

JavaScript Code复制内容到剪贴板
  1. //实时监控数据  
  2. computed: {  
  3.     categorys() {  
  4.         return this.$store.state.category.categoryData;  
  5.     }  
  6. },  

 

 


 

demo1:检测标题是否重复

 

需捕捉异步后回调需要加await,需要使用异步的方法,或者函数,需要加async:

JavaScript Code复制内容到剪贴板
  1. async checkTitle() {    
  2.         
  3.             // 检测标题是否重复  
  4.             let checkparams = {  
  5.                 type: 1,  
  6.                 id: this.linkId,  
  7.                 title: this.course_name  
  8.             };  
  9.             try {  
  10.                 await this.$store.dispatch("course/uniquenessTitle", checkparams); // 这里得到了一个返回错误  
  11.                 this.titleFocusActive = false// 失去焦点  
  12.                 this.titleIfCheck = true// 标题检测成功  
  13.             } catch (err) {  
  14.                 let instance = this.$toast(this.$t("course.titleAlreadyExisted"));  
  15.                 setTimeout(() => {  
  16.                     instance.close();  
  17.                     this.titleFocusActive = true// 聚焦  
  18.                     this.titleIfCheck = false// 标题检测失败  
  19.                 }, 1000);  
  20.                 // console.log(err); // 这里捕捉到错误 `error`  
  21.                 return false;  
  22.             }  
  23.             // 检测end  
  24.   
  25. },    

 

 

(参照ele后台方法)action:

JavaScript Code复制内容到剪贴板
  1. // 获取用户信息  
  2. GetUserInfo({ commit, state }) {  
  3.   return new Promise((resolve, reject) => {  
  4.     getUserInfo(state.token).then(response => {  
  5.       if (!response.data) { // 由于mockjs 不支持自定义状态码只能这样hack  
  6.         reject('error')  
  7.       }  
  8.       const data = response.data  
  9.       commit('SET_ROLES', data.roles)  
  10.       commit('SET_NAME', data.name)  
  11.       commit('SET_AVATAR', data.avatar)  
  12.       commit('SET_INTRODUCTION', data.introduction)  
  13.       resolve(response)  
  14.     }).catch(error => {  
  15.       reject(error)  
  16.     })  
  17.   })  
  18. },  

 

demo2:检测是否有列表数据

vue文件中的方法:

JavaScript Code复制内容到剪贴板
  1. async chooseCourse() {  
  2.     // 选择资料的同时,保存当前路由和详情以前发布ID  
  3.     this.insertSession();  
  4.       
  5.     // 检测是否有问卷列表数据  
  6.     let params= {  
  7.         pageIndex: 1,  
  8.         pageSize: 30,  
  9.         courseId: this.$route.params.courseId, //测试的时候 可以将课程id隐藏  
  10.         userId: this.$store.state.common.userId  
  11.     };  
  12.     let res = await this.$store.dispatch("course/checkExamination",params);  
  13.     if(!res){  
  14.         return false;  
  15.     }  
  16.     // 检测end  

 

在分模块中的courseModule中,添加action:

JavaScript Code复制内容到剪贴板
  1. checkExamination({ commit, state,rootState },params){  
  2.     if(!params){  
  3.         params = {};  
  4.     }  
  5.     let sendData = {};  
  6.       
  7.     sendData.pageIndex = params.hasOwnProperty("pageIndex") ? params.pageIndex : 1; // 页码  
  8.     sendData.pageSize = params.hasOwnProperty("pageSize") ? params.pageSize : 15; // 个数  
  9.     sendData.user_id = params.hasOwnProperty("userId") ? params.userId : rootState.common.userId; // 当前用户  
  10.     sendData.course_id = params.hasOwnProperty("courseId") ? params.courseId : 0;  
  11.       
  12.     let api = rootState.exam.api.getExamList;  
  13.        return new Promise((resolve, reject) => {  
  14.            request.post(api, sendData).then(response => {  
  15.                if (!response) {  
  16.                    return false;  
  17.                }  
  18.                  
  19.                let data = response.result;  
  20.            
  21.                if(data.length == 0){  
  22.                   
  23.                    MessageBox.confirm('还没有试卷,先去创建吧!').then(action=>{  
  24.                        router.push("/exam/question-paper-lib");  
  25.                    }).catch(err=>{});  
  26.                      
  27.                    resolve(false);  
  28.                      
  29.                }else{  
  30.                   
  31.                 resolve(response)  
  32.                   
  33.                }  
  34.                  
  35.            })  
  36.        });  
  37.          
  38. },  

 

 


 

 

在 Vue.js 的项目中,如果项目结构简单, 父子组件之间的数据传递可以使用 props 或者 $emit 等方式

但是如果是大型项目,很多时候都需要在子组件之间传递数据,使用之前的方式就不太方便。Vue 的状态管理工具 Vuex 完美的解决了这个问题。

一、安装并引入 Vuex

项目结构:

1059788-20170204141223370-462995386.png

首先使用 npm 安装 Vuex

C/C++ Code复制内容到剪贴板
  1. cnpm install vuex -S  

 

然后在 main.js 中引入(与参考资料中有出入,视情况而定)

PHP Code复制内容到剪贴板
  1. import Vue from 'vue'  
  2. import App from './App'  
  3.   
  4. import store from './vuex/store' ##引用  
  5.   
  6.   
  7. /* eslint-disable no-new */  
  8. new Vue({  
  9.   el: '#app',  
  10.   store,  
  11.   render: h => h(App)  
  12. })  

 

 在 src 目录下创建一个 vuex 目录,将 store.js 放到 vuex 目录下

PHP Code复制内容到剪贴板
  1. import Vue from 'vue'  
  2. import Vuex from 'vuex'  
  3.   
  4. Vue.use(Vuex)  
  5.   
  6. const store = new Vuex.Store({  
  7.   // 定义状态  
  8.   state: {  
  9.     author: 'Wise Wrong'  
  10.   }  
  11. })  
  12.   
  13. export default store  

 

 将状态映射到组件

JavaScript Code复制内容到剪贴板
  1. <template>  
  2.   <footer class="footer">  
  3.     <ul>  
  4.       <li v-for="lis in ul">{{lis.li}}</li>  
  5.     </ul>  
  6.     <p>  
  7.       Copyright © {{author}} - 2016 All rights reserved  
  8.     </p>  
  9.   </footer>  
  10. </template>  
  11.   
  12. <script>  
  13.   export default {  
  14.     name: 'footerDiv',  
  15.     data () {  
  16.       return {  
  17.         ul: [  
  18.           { li: '琉璃之金' },  
  19.           { li: '朦胧之森' },  
  20.           { li: '缥缈之滔' },  
  21.           { li: '逍遥之火' },  
  22.           { li: '璀璨之沙' }  
  23.         ]  
  24.       }  
  25.     },  
  26.     computed: {  
  27.       author () {  
  28.         return this.$store.state.author  
  29.       }  
  30.     }  
  31.   }  
  32. </script>  

这是 footer.vue 的 html 和 script 部分

主要在 computed 中,将 this.$store.state.author 的值返回给 html 中的 author

页面渲染之后,就能获取到 author 的值

 

在组件中修改状态

然后在 header.vue 中添加一个输入框,将输入框的值传给 store.js 中的 author

这里我使用了 Element-UI 作为样式框架

1059788-20170204144117323-2099253314.png

上面将输入框 input 的值绑定为 inputTxt,然后在后面的按钮 button 上绑定 click 事件,触发 setAuthor 方法

JavaScript Code复制内容到剪贴板
  1. methods: {  
  2.  setAuthor: function () {  
  3.    this.$store.state.author = this.inpuTxt  
  4.  }  
  5. }  

在 setAuthor 方法中,将输入框的值 inputTxt 赋给 Vuex 中的状态 author,从而实现子组件之间的数据传递

 

官方推荐的修改状态的方式

 

上面的示例是在 setAuthor 直接使用赋值的方式修改状态 author,但是 vue 官方推荐使用下面的方法:

1059788-20170204150217073-1166548030.png

JavaScript Code复制内容到剪贴板
  1. mutations: {  
  2.     newAuthor(state, msg) {  
  3.         state.author = msg;  
  4.     }  
  5. }  

 

然后修改 header.vue 中的 setAuthor 方法

PHP Code复制内容到剪贴板
  1. this.$store.commit('newAuthor','123');  

 

这里使用 $store.commit 提交 newAuthor,并将 this.inputTxt 传给 msg,从而修改 author

 

这样显式地提交(commit) mutations,可以让我们更好的跟踪每一个状态的变化,所以在大型项目中,更推荐使用第二种方法。

添加actions方法,全局函数 :

JavaScript Code复制内容到剪贴板
  1. import Vue from 'vue'  
  2. import Vuex from 'vuex'  
  3. import axios from 'axios'  
  4.   
  5. Vue.use(Vuex)  
  6.   
  7. const store = new Vuex.Store({  
  8.   
  9.     actions: {  
  10.   
  11.         getCategoryData() {  
  12.             return axios.get(this.state.api.getCategory);  
  13.         }  
  14.   
  15.     }  
  16.   
  17. })  

 

 

 

 

本文来自于:http://www.yoyo88.cn/study/vue/154.html

Powered by yoyo苏ICP备15045725号