美文网首页
vuex 设计

vuex 设计

作者: JasonFF | 来源:发表于2017-10-23 09:43 被阅读70次

    先来看一下标准的 vuex demo

    • vuex 的状态管理:
      state => getters => view => action => commit => mutations => state(new) => getters => view(new)

    demo (from demo)

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    const state = {
      count: 0
    }
    
    const mutations = {
      increment (state) {
        state.count++
      },
      decrement (state) {
        state.count--
      }
    }
    
    const actions = {
      increment: ({ commit }) => commit('increment'),
      decrement: ({ commit }) => commit('decrement'),
      incrementIfOdd ({ commit, state }) {
        if ((state.count + 1) % 2 === 0) {
          commit('increment')
        }
      },
      incrementAsync ({ commit }) {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            commit('increment')
            resolve()
          }, 1000)
        })
      }
    }
    
    const getters = {
      evenOrOdd: state => state.count % 2 === 0 ? 'even' : 'odd'
    }
    
    export default new Vuex.Store({
      state,
      getters,
      actions,
      mutations
    })
    
    

    airforce 的封装设计

    airforce.js

    import { login } from '../api/login'
    import initialState from './initialState'
    import _ from 'lodash'
    
    const AIRFORCE_DO = 'AIRFORCE_DO'
    const AIRFORCE_LEAVE = 'AIRFORCE_LEAVE'
    
    const apis = {
      login
    }
    
    const state = initialState
    
    const getters = {
      airforce: state => state
    }
    
    // data = {
    //   moduleName: 'abc',
    //   apiName: 'login',
    //   apiConfig: {
    //     loginName: 'login',
    //     password: '123456'
    //   },
    //   goods: {
    //     loginFlag: true
    //   }
    // }
    
    const actions = {
      action ({ commit }, data) {
        if (data.loading) {
          VUX.loading.show({
             text: ''
          })
        }
        if (data.apiName) {
          if (typeof apis[data.apiName] !== 'function') {
            return console.error('no matching apiName.')
          }
          apis[data.apiName](data.apiConfig).then(res => {
            let result
            try {
              result = res.json()
            } catch (e) {}
            if (result) {
              return result
            }
            return res
          }).then(result => {
            if (data.loading) {
               VUX.loading.hide()
            }
            if (typeof result.data === 'object') {
              data.goods = _.merge(data.goods, result.data)
            } else {
              data.goods.$resData = result.data
            }
    
            commit(AIRFORCE_DO, { data })
            if (data.callback) {
              data.callback(result.data)
            }
            if (result.status >= 200 && result.status < 300 && result.data.status !== 'ERROR') {
              return Promise.resolve(result.data)
            } else {
              return Promise.reject(result)
            }
          }).then(res => {
            if (data.success) {
              data.success(res)
            }
            return res
          }).catch(e => {
            if (data.loading) {
               VUX.loading.hide()
            }
            if (data.error) {
              data.error(e)
            }
            if (!data.noError && e.data && e.data.message) {
               VUX.toast.text(e.data.message)
            }
            return Promise.reject(e)
          })
        } else {
          commit(AIRFORCE_DO, { data })
        }
      },
      unload ({ commit }, data) {
        commit(AIRFORCE_LEAVE, { data })
      }
    }
    
    // mutations
    const mutations = {
      [AIRFORCE_DO] (state, { data }) {
        if (typeof data.goods === 'object') {
          state[data.moduleName] = _.merge(state[data.moduleName], data.goods)
        } else {
          state[data.moduleName] = data.goods
        }
      },
      [AIRFORCE_LEAVE] (state, { data }) {
        state[data.moduleName] = undefined
      }
    }
    
    export default {
      state,
      getters,
      actions,
      mutations
    }
    

    initialState.js

    export default {
      abc: {
        b: {
          c: 'abc',
          d: 3
        }
      }
    }
    

    initial state 结构确定了整个 state 响应式属性的内容

    • 官网的对于响应式原理的解释:


      image.png

    login.js

    import { fetch } from '../utils/fetch'
    
    export function login ({username, password}) {
      const data = {
        username,
        password
      }
      return fetch({
        url: '/login',
        method: 'post',
        params: data
      })
    }
    export function logout () {
      return fetch({
        url: '/logout',
        method: 'post'
      })
    }
    

    Promise.all 的设计

    const a = this.action({
      apiName: 'login'
    })
    const b = this.action({
      apiName: 'getConfig'
    })
    Promise.all([a,b]).then(res=>{
       console.log('init')
    })
    

    模块化设计

    import Vue from 'vue'
    import _ from 'lodash'
    import axios from './axios'
    import initState from './initState'
    
    const AIRFORCE_DO = 'AIRFORCE_DO'
    const AIRFORCE_LEAVE = 'AIRFORCE_LEAVE'
    const AIRFORCE_SET = 'AIRFORCE_SET'
    
    // initial state
    const state = initState
    
    // getters
    const getters = {
      airforce: state => {
        const airforce = {
          '$$global': {}
        }
        for (let i in state) {
          if (state[i].__fromModule) {
            _.set(airforce, `${[state[i].__fromModule]}.${i}`, state[i])
          } else {
            airforce.$$global[i] = state[i]
          }
        }
        return {
          ...state,
          ...airforce
        }
      }
    }
    
    // actions
    const actions = {
      action ({ commit }, data) {
        if (data.loading) {
          // VUX.loading.show({
          //   text: ''
          // })
        }
        const {goods, ...restData} = data
        if (data.method && (data.url || data.fullUrl)) {
          if (!data.goods) {
            data.goods = {}
          }
          return axios(restData).then(res => {
            let result
            try {
              result = res.json()
            } catch (e) {}
            if (result) {
              return result
            }
            return res
          }).then(result => {
            if (data.loading) {
              // VUX.loading.hide()
            }
            if (_.isObject(result.data) && !_.isArray(result.data)) {
              data.goods = _.merge({}, data.goods, result.data)
            } else {
              _.set(data, 'goods.$resData', result.data)
            }
    
            commit(AIRFORCE_DO, data)
            if (data.callback) {
              data.callback(result.data)
            }
            if (result.status >= 200 && result.status < 300 && result.data.status !== 'ERROR') {
              return Promise.resolve(result.data)
            } else {
              return Promise.reject(result)
            }
          }).then(res => {
            if (data.success) {
              data.success(res)
            }
            return res
          }).catch(e => {
            console.log(e)
            if (data.loading) {
              // VUX.loading.hide()
            }
            if (data.error) {
              data.error(e)
            }
            if (!data.noError && e.data && e.data.message) {
              // VUX.toast.text(e.data.message)
            }
            return Promise.reject(e)
          })
        }
        commit(AIRFORCE_DO, data)
      },
      unload ({ commit }, data) {
        commit(AIRFORCE_LEAVE, data)
      },
      stateSet ({ commit }, data) {
        commit(AIRFORCE_SET, data)
      }
    }
    
    // mutations
    const mutations = {
      [AIRFORCE_DO] (state, data) {
        if (_.isObject(data.goods) && !_.isArray(data.goods)) {
          Vue.set(state, data.moduleName, _.merge({__fromModule: '$$' + window.location.hash.replace(/^#\//, '')}, state[data.moduleName], data.goods))
        } else {
          Vue.set(state, data.moduleName, data.goods)
        }
        console.group()
        console.log('action', data)
        console.log('airforce', state)
        console.groupEnd()
        if (state.syncHeight) {
          state.syncHeight()
        }
      },
      [AIRFORCE_LEAVE] (state, data) {
        state[data.moduleName] = undefined
        if (state.syncHeight) {
          state.syncHeight()
        }
      },
      [AIRFORCE_SET] (state, data) {
        data(state)
        if (state.syncHeight) {
          state.syncHeight()
        }
      }
    }
    
    export default {
      state,
      getters,
      actions,
      mutations
    }
    
    
    export function mapAirforce (arr) {
      const result = {}
      for (let i = 0; i < arr.length; i++) {
        const item = arr[i]
        Object.assign(result, {
          [item] () {
            return _.get(this.$store.getters.airforce, `$$${item}`)
          }
        })
      }
      return result
    }
    
    

    用法

    import {mapAirforce} from '@/widgets'
    ...
    computed: {
        ...mapAirforce(['merchantOrderList'])
      },
    ...
    // this.merchantOrderList就是改路由模块下的数据
    

    相关文章

      网友评论

          本文标题:vuex 设计

          本文链接:https://www.haomeiwen.com/subject/syeouxtx.html