Gitee 地址

https://gitee.com/rayleighvickecn/dict

github 地址

https://github.com/rayleighzhao/dict

简介

管理下拉列表的函数: customOwnKeys

管理过滤器用到三个函数: mapDictFilter、mapAsyncDictFilter、mapAsyncDictInit

字典数据

定义在Vuex

@/store/modules/dict.js

import { customOwnKeys } from '@/utils'

function mutationFunc(key) {
  return function mutation(state, val) {
    state[key] = val
  }
}

export default {
  namespaced: true,
  state() {
    return {
      customOwnKeysStatus1: customOwnKeys({
        '01': '壹',
        '09': '玖',
        '11': '拾壹',
        '21': '廿壹',
        // [customOwnKeys.ID]: ['01','09','11','21']
      }, /*(a, b) => String(a) > String(b) ? 1 : -1 */),
      status2: {
        '001': '状态2-1',
        '002': '状态2-2',
      },
      asyncStatus3: {
        '003': '状态3-3',
        '004': '状态3-4',
      },
      asyncStatus4: {
        '003': '状态4-3',
        '004': '状态4-4',
      },
      asyncStatus5: {
        '003': '状态5-3',
        '004': '状态5-4',
      },
    }
  },
  getters: {},
  mutations: {
    setAsyncStatus3: mutationFunc('asyncStatus3'),
    setAsyncStatus4: mutationFunc('asyncStatus4'),
    setAsyncStatus5: mutationFunc('asyncStatus5'),
  },
  actions: {
    setAsyncStatus3(context) {
      setTimeout(() => {
        context.commit('setAsyncStatus3', {
          '003': '状态3-33',
          '004': '状态3-44',
        })
      }, 2000)
    },
    setAsyncStatus4(context) {
      setTimeout(() => {
        context.commit('setAsyncStatus4', {
          '003': '状态4-33',
          '004': '状态4-44',
        })
      }, 2000)
    },
    setAsyncStatus5(context) {
      setTimeout(() => {
        context.commit('setAsyncStatus5', {
          '003': '状态5-33',
          '004': '状态5-44',
        })
      }, 2000)
    }
  },
}

customOwnKeys

用法一: key转换成字符串, 按Unicode排序

customOwnKeysStatus1: customOwnKeys({
  '01': '壹',
  '09': '玖',
  '11': '拾壹',
  '21': '廿壹',
}),

用法二:

customOwnKeysStatus1: customOwnKeys({
  '01': '壹',
  '09': '玖',
  '11': '拾壹',
  '21': '廿壹',
  [customOwnKeys.ID]: ['01','09','11','21']
}),

用法三:

customOwnKeysStatus1: customOwnKeys({
  '01': '壹',
  '09': '玖',
  '11': '拾壹',
  '21': '廿壹',
}, ['01','09','11','21']),

用法四: 同 Array.prototype.sort

customOwnKeysStatus1: customOwnKeys({
  '01': '壹',
  '09': '玖',
  '11': '拾壹',
  '21': '廿壹',
}, (a, b) => String(a) > String(b) ? 1 : -1),

自定义顺序下拉列表示例

<select name="customOwnKeysStatus1" id="customOwnKeysStatus1" v-model="customOwnKeysStatus1Value">
  <option value="" selected>全部</option>
  <option v-for="(value, key) in customOwnKeysStatus1" :key="key" :value="key">{{value}}</option>
</select>
data() {
  return {
    customOwnKeysStatus1Value: '',
  }
},
computed: {
  ...mapState('dict', ['customOwnKeysStatus1']),
},

mapDictFilter

vue2用法

<td>{{item.status | status2}}<td>
filters: {
  ...mapDictFilter(['status2'])
}

vue3用法

<td>{{status2(item.status)}}<td>
methods: {
  ...mapDictFilter(['status2'])
}

mapAsyncDictFilter

vue2用法

<td>{{item.asyncStatus3 | asyncStatus3}}</td>
methods: {
  ...mapActions('dict', ['setAsyncStatus3'])
},
filters: {
  ...mapDictFilter(['asyncStatus3']),
},
watch: {
  ...mapAsyncDictFilter(['asyncStatus3'])
},
created() {
  this.setAsyncStatus3()
},

vue3用法

<td>{{asyncStatus3(item.asyncStatus3)}}</td>
methods: {
  ...mapActions('dict', ['setAsyncStatus3'])
},
watch: {
  ...mapAsyncDictFilter(['asyncStatus3']),
},
created() {
  this.setAsyncStatus3()
},

mapAsyncDictInit callback 是 function

因为 mapAsyncDictFilter 是异步获得, 存在数据先获得而字典后获得不同步的问题, 所以用 mapAsyncDictInit 更稳妥, 数组 [{dictName: 'asyncStatus4', asyncName: 'setAsyncStatus4'}] 字典并发获取, 全部获取完了才运行 callback

vue2用法

<td>{{item.asyncStatus4 | asyncStatus4}}</td>

vue3用法

<td>{{asyncStatus4(item.asyncStatus4)}}</td>

js 部分无差别

mounted: mapAsyncDictInit([{dictName: 'asyncStatus4', asyncName: 'setAsyncStatus4'}], function() {
  const list = [
    {id: 1, asyncStatus4: '003'},
    {id: 2, asyncStatus4: '004'},
    {id: 3, asyncStatus4: '004'},
    {id: 4, asyncStatus4: '003'},
  ]
  setTimeout(() => this.list = list, 2000)
})

mapAsyncDictInit callback 是 { push, pop }

push 函数和 [{dictName: 'asyncStatus5', asyncName: 'setAsyncStatus5'}] 字典数组并发获取, push 函数获取的结果后, 运行 pop 函数, 第一个参数就是获得的结果

vue2用法

<td>{{item.asyncStatus5 | asyncStatus5}}</td>

vue3用法

<td>{{asyncStatus5(item.asyncStatus5)}}</td>

js 部分无差别

mounted: mapAsyncDictInit([{dictName: 'asyncStatus5', asyncName: 'setAsyncStatus5'}], {
  push() {
    return new Promise(
      resolve => setTimeout(
        () => resolve([
          {id: 1, asyncStatus5: '003'},
          {id: 2, asyncStatus5: '004'},
          {id: 3, asyncStatus5: '004'},
          {id: 4, asyncStatus5: '003'},
        ])
        ,
        2000
      )
    )
  },
  pop(data) {
    this.list = data
  }
})

customOwnKeys 源码

@/utils/index.js

export function customOwnKeys(obj, config) {
  return new Proxy(obj, {
    ownKeys() {
      const keys = obj[customOwnKeys.ID] || []
      if(keys.length > 0) {
        return keys
      } else if(config && Array.isArray(config)) {
        return config
      } else if(isFunc(config)) {
        return Reflect.ownKeys(obj).sort(config)
      } else {
        return Reflect.ownKeys(obj).sort()
      }
    }
  })
}
customOwnKeys.ID = Symbol.for('customOwnKeys')

mapDictFilter、mapAsyncDictFilter、mapAsyncDictInit 源码

vue2 和 vue3 只是 $getObj 部分不同

@/filters/dict.js

import store from '@/store'
import { isFunc } from '@/utils'

const $state = store.state
const $getters = store.getters
const $dispatch = store.dispatch
const $dict = dictName => {
  if($state.dict && $state.dict[dictName]) {
    return $state.dict[dictName]
  } else if($getters[`dict/${dictName}`]) {
    return $getters[`dict/${dictName}`]
  }
}
const $keyName = dictName => {
  if($state.dict && $state.dict[dictName]) {
    return `$store.state.dict.${dictName}`
  } else if($getters[`dict/${dictName}`]) {
    return `$store.getters.dict/${dictName}`
  }
}
// vue2
const $getObj = that => that.$options.filters
// // vue3
// const $getObj = that => that

function commonFilter(dictName) {
  return function filter(val) {
    return dictName[val] || val || '未知'
  }
}

function commonAsyncFilter(key, callback) {
  return function watch(dictName) {
    const obj = $getObj(this)
    obj[key] = commonFilter(dictName)
    if (isFunc(callback)) {
      callback()
    }
  }
}

function commonMap(keyFunc, func) {
  return function map(arr) {
    const returnObj = {}
    arr.forEach(key => {
      returnObj[keyFunc(key)] = func(key)
    })
    return returnObj
  }
}

export const mapDictFilter = commonMap( key => key, key => commonFilter($dict(key)) )

export const mapAsyncDictFilter = commonMap( key => $keyName(key), key => commonAsyncFilter(key) )

export function mapAsyncDictInit(arr, callback) {
  return function init() {
    const length = arr.length
    const promises = arr.map(({ dictName, asyncName }) => new Promise(resolve => {
      const obj = $getObj(this)
      obj[dictName] = commonFilter($dict(dictName))
      this.$watch($keyName(dictName), commonAsyncFilter(dictName, resolve))
      $dispatch(`dict/${asyncName}`)
    }))
    if(isFunc(callback)) {
      Promise.all(promises).then(callback.bind(this))
    } else {
      const { push = null, pop = null } = callback || {}
      const promise = Promise.resolve()
      if(isFunc(push)) {
        promises.push(promise.then(push.bind(this)))
      }
      const result = Promise.all(promises)
      if(isFunc(pop)) {
        result
        .then(datas => datas[length])
        .then(pop.bind(this))
      }
    }
  }
}
03-05 21:07