发表于: 2019-11-07 21:34:31
1 1148
今天完成的事情:
1.学习了vuex:
1,核心概念
1.1 State: 用于数据的存储,是store中的唯一数据源,类似vue中data对象.
- 单一状态树:用一个对象就包含了所有应用层级状态.每个应用就只包含一个store实例.
- 计算属性:由于Vuex的状态储存是响应式的,从store实例中读取状态最简单的方法就是在计算属性中返回某个状态(例如token).
- 使用方法:
// 定义 new Vuex.Store({ state: { bilibili: { acFun:"我还想再活五百年" } } //... }) // 组件中获取 this.$store.state.bilibili.acFun 复制代码
Tips:如果某个state是作为公共状态给多个组件使用,且不想被修改后污染其他组件.这时可以将state写成return形式,类似vue中data一样.(仅2.30+以上支持)
state(){ return{ bilibili: { acFun:"我还想再活五百年" } } } 复制代码
1.2 Module: 将store分割成不同的模块,方便管理维护
- 可以将store分割成模块(module).每个模块拥有自己的state,mutation,action,getter,甚至嵌套子模块--从上至下进行同样的方式的分割.
- 使用方法:
// 定义 const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) // 组件中使用 store.state.a // -> moduleA 的状态 store.state.b // -> moduleB 的状态 复制代码
1.3 Getter: 对共享数据进行过滤获取
- 当需要对 store 中的数据进行处理,或者数据被多个组件复用,就可以使用 Getters 来处理,Getters 也可以理解为 Vue 中的计算属性 (computed),其实就是基于state数据的再包装。
- getter的返回值会根据它的依赖被缓存起来.
- 使用方法:
// 定义,第一个参数为该模块下的state;第二个参数getters为store里的getters.注意getters是没有按模块进行区分的;第三个参数rootState顾名思义就是根state getters: { cartProducts(state, getters, rootState) => (getters.allProducts.filter(p => p.quantity)), dateFormat(state, getters) { let date = state.nowDate; return `${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()} / ${date.getHours()}:${date.getMinutes()}`; } } // 组件中获取 this.$store.getters.cartProducts //补充:由于getters会缓存结果.如果你不想缓存,或者想对getters进行传参,此时则需要用函数形式写getter. getters:{ //... test:(state)=>(param)=>{ return state.todos.find(todo=>todo.id===id) } } 复制代码
1.4 Mutation: 改变state的唯一方法
- 每个mutation都有一个字符串的事件类型(type) 和一个 回调函数
- mutation必须是同步函数
- mutation不能包含异步操作
- 由于store中状态是响应式的,那么在修改时,mutation也应该满足vue响应式的一些注意事项:
- 最好提前在你的 store 中初始化好所有所需属性。
- 当需要在对象上添加新属性时,你应该
使用 Vue.set(obj, ‘newProp’, 123),或者
以新对象替换老对象
.例如,利用 stage-3 的对象展开运算符我们可以这样写:
state.obj = { ...state.obj, newProp: 123 } 复制代码
- mutation是修改state的唯一方法,并且mutations不能直接调用,而要通过相应type调用store.commit.
- 使用方法:
// 定义 第一个参数state为该模块下的state;第二个参数products为调用时的传参 mutations: { setProducts (state, products) { state.allProducts = products } } // 组件中提交方式可以分为三种,其实前两种都是载荷(payload),第三种是对象形式 //第一种 直接在后面加上要传入的参数 this.$store.commit('setProducts', 'GodOfWar4') //第二种 直接在后面加上要传入的参数 this.$store.commit('setProducts', { name:'GodOfWar4', comment:"我TM射爆!" }) //注意:此时mutation,setProducts 就要修改为下面形式 setProducts (state, products) { state.allProducts = products.name //要改为这种写法 } //第三种 将state类别作为对象的属性,和参数一起提交 this.$store.commit({ type:'setProducts', name:'GodOfWar4', comment:"我TM射爆!" }) //此时mutation的写法和第二种情况一样. 复制代码
1.5 Action: 可以使用异步操作提交mutation
- action提交的是mutation,而不是直接变更状态.action可以包含异步操作
- action通过store.dispatch触发(异步)
- action返回的是promise
- 如果是state的数据就使用actions请求数据,建议数据处理也放在actions中,或者放在getter中进行数据处理.mutations只做state的修改.
- 使用方法:
state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { //只是提交`commit`了`mutations`里面的方法。 increment (context,payload) { context.commit('increment') } } // 一般我们会通过解构简写成这样 actions: { increment ({ commit },payload) { commit('increment') } } // 在组件中使用,同mutation,只是由commit变为dispatch this.$store.dispatch('increment', {//..payload}) //这里需要说明的是第一个参数context就是上下文,context是一个store对象,你也可以用解构的方式写出来,第二个参数payload是我们的传参,同mutation一样. //那么context究竟包含了哪些?通过源码可以清楚看到: let res = handler({ dispatch, commit, getters: store.getters, state: getNestedState(store.state, path), rootState: store.state }, payload, cb) //可以看出context包括5个属性:dispatch,commit,getters,state,rootState. //故我们可以通过解构的方式{commit,dispatch,state}只取我们需要的属性. 复制代码
- 组合 Action (完全照搬官网说明)
Action 通常是异步的,那么如何知道 action 什么时候结束呢?更重要的是,我们如何才能组合多个 action,以处理更加复杂的异步流程?
首先,你需要明白 store.dispatch
可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch
仍旧返回 Promise:
actions: { actionA ({ commit }) { return new Promise((resolve, reject) => { setTimeout(() => { commit('someMutation') resolve() }, 1000) }) } } 复制代码
现在你可以:
store.dispatch('actionA').then(() => { // ... }) 复制代码
在另外一个 action 中也可以:
actions: { // ... actionB ({ dispatch, commit }) { return dispatch('actionA').then(() => { commit('someOtherMutation') }) } } 复制代码
最后,如果我们利用 async / await,我们可以如下组合 action:
// 假设 getData() 和 getOtherData() 返回的是 Promise actions: { async actionA ({ commit }) { commit('gotData', await getData()) }, async actionB ({ dispatch, commit }) { await dispatch('actionA') // 等待 actionA 完成 commit('gotOtherData', await getOtherData()) } } 复制代码
一个
store.dispatch
在不同模块中可以触发多个 action 函数。在这种情况下,只有当所有触发函数完成后,返回的 Promise 才会执行。
Tips:
有一点要注意的是,将 store 中的 state 绑定到 Vue 组件中的 computed 计算属性后,对 state 进行更改需要通过 mutation 或者 action,在 Vue 组件中直接进行赋值 (this.myState = ‘ABC’) 是不会生效的。
在 Vuex 模块化中,state 是唯一会根据组合时模块的别名来添加层级的,后面的 getters、mutations 以及 actions 都是直接合并在 store 下。
由于vuex是单向数据流,vue中v-model是双向绑定.所以当v-model绑定的数据时vuex时,需要监听实时修改vuex中的数据.
明天计划:
1.把vuex运用到页面数据里,进行页面数据跨组件共享。
评论