美文网首页
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