若依vue中字典执行过程浅析

1.导入并使用插件DataDict
/**
 * file:src/main.js
 */
// 字典数据组件 
import DictData from '@/components/DictData'
DictData.install()
/**
 *file:src/components/DictData/index.js
 */
import Vue from 'vue'
import DataDict from '@/utils/dict'
import { getDicts as getDicts } from '@/api/system/dict/data'

function install() {
  Vue.use(DataDict, {
    metas: {
      '*': {
        labelField: 'dictLabel',
        valueField: 'dictValue',
        request(dictMeta) { //注意这个
          return getDicts(dictMeta.type).then(res => res.data)
        },
      },
    },
  })
}

export default {
  install,
}
2. DataDict初始化字典数据 , 混入dict,传给监听器回调
//file:src/utils/dict/index.js
import Dict from './Dict'
import { mergeOptions } from './DictOptions'

export default function(Vue, options) {
  mergeOptions(options)
  Vue.mixin({
    data() {
      if (this.$options === undefined || this.$options.dicts === undefined || this.$options.dicts === null) {
        return {}
      }
      const dict = new Dict()
      dict.owner = this
      return {
        dict
      }
    },
    created() {
      if (!(this.dict instanceof Dict)) {
        return
      }
      options.onCreated && options.onCreated(this.dict)
      this.dict.init(this.$options.dicts).then(() => {
        options.onReady && options.onReady(this.dict)
        this.$nextTick(() => {
          this.$emit('dictReady', this.dict)
          if (this.$options.methods && this.$options.methods.onDictReady instanceof Function) {
            this.$options.methods.onDictReady.call(this, this.dict)
          }
        })
      })
    },
  })
}

3. dict.init(this.$options.dicts) 给dict 赋值
import Vue from 'vue'
import { mergeRecursive } from "@/utils/rytech";
import DictMeta from './DictMeta'
import DictData from './DictData'

const DEFAULT_DICT_OPTIONS = {
  types: [],
}

/**
 * @classdesc 字典
 * @property {Object} label 标签对象,内部属性名为字典类型名称
 * @property {Object} dict 字段数组,内部属性名为字典类型名称
 * @property {Array.<DictMeta>} _dictMetas 字典元数据数组
 */
export default class Dict {
  constructor() {
    this.owner = null
    this.label = {}
    this.type = {}
  }

  init(options) {
    if (options instanceof Array) {
      options = { types: options }
    }
    const opts = mergeRecursive(DEFAULT_DICT_OPTIONS, options)
    if (opts.types === undefined) {
      throw new Error('need dict types')
    }
    const ps = []
    this._dictMetas = opts.types.map(t => DictMeta.parse(t))
    this._dictMetas.forEach(dictMeta => {
      const type = dictMeta.type
      Vue.set(this.label, type, {})
      Vue.set(this.type, type, [])
      if (dictMeta.lazy) {
        return
      }
      ps.push(loadDict(this, dictMeta))
    })
    return Promise.all(ps)
  }

  /**
   * 重新加载字典
   * @param {String} type 字典类型
   */
  reloadDict(type) {
    const dictMeta = this._dictMetas.find(e => e.type === type)
    if (dictMeta === undefined) {
      return Promise.reject(`the dict meta of ${type} was not found`)
    }
    return loadDict(this, dictMeta)
  }
}

/**
 * 加载字典
 * @param {Dict} dict 字典
 * @param {DictMeta} dictMeta 字典元数据
 * @returns {Promise}
 */
function loadDict(dict, dictMeta) {
  return dictMeta.request(dictMeta)
    .then(response => {
      const type = dictMeta.type
      let dicts = dictMeta.responseConverter(response, dictMeta)
      if (!(dicts instanceof Array)) {
        console.error('the return of responseConverter must be Array.<DictData>')
        dicts = []
      } else if (dicts.filter(d => d instanceof DictData).length !== dicts.length) {
        console.error('the type of elements in dicts must be DictData')
        dicts = []
      }
      dict.type[type].splice(0, Number.MAX_SAFE_INTEGER, ...dicts)
      dicts.forEach(d => {
        Vue.set(dict.label[type], d.value, d.label)
      })
      return dicts
    })
}

先判断了是不是数组
我这里this.$options.dicts是字典类型的数组
在这里插入图片描述
然后给了opt.types
用 mergeRecursive 将opt.types合并到 DEFAULT_DICT_OPTIONS

// 数据合并
export function mergeRecursive(source, target) {
    for (var p in target) {
        try {
            if (target[p].constructor == Object) {
                source[p] = mergeRecursive(source[p], target[p]);
            } else {
                source[p] = target[p];
            }
        } catch(e) {
            source[p] = target[p];
        }
    }
    return source;
};

执行了
this._dictMetas = opts.types.map(t => DictMeta.parse(t))
然后loadDict(this, dictMeta)
load中调用了dictMeta.request

request(dictMeta) { 
          return getDicts(dictMeta.type).then(res => res.data)
        }

最后push到空数组ps中统一执行

4.DictMeta 字典元数据
/**
 * @classdesc 字典元数据
 * @property {String} type 类型
 * @property {Function} request 请求
 * @property {String} label 标签字段
 * @property {String} value 值字段
 */
export default class DictMeta {
  constructor(options) {
    this.type = options.type
    this.request = options.request,
    this.responseConverter = options.responseConverter
    this.labelField = options.labelField
    this.valueField = options.valueField
    this.lazy = options.lazy === true
  }
}


/**
 * 解析字典元数据
 * @param {Object} options
 * @returns {DictMeta}
 */
DictMeta.parse= function(options) {
  let opts = null
  if (typeof options === 'string') {
    opts = DictOptions.metas[options] || {}
    opts.type = options
  } else if (typeof options === 'object') {
    opts = options
  }
  opts = mergeRecursive(DictOptions.metas['*'], opts)
  return new DictMeta(opts)
}
5.DictOptions DictMeta的配置项

DictOptions是一个DictMeta的一个默认配置项
这里提供了默认的labelField等和一个请求函数和映射转换函数 要注意的是 labelField,valueField,request在上面已经被赋值了
如下

import { mergeRecursive } from "@/utils/rytech";
import dictConverter from './DictConverter'

export const options = {
  metas: {
    '*': {
      /**
       * 字典请求,方法签名为function(dictMeta: DictMeta): Promise
       */
      request: (dictMeta) => {
        console.log(`load dict ${dictMeta.type}`)
        return Promise.resolve([])
      },
      /**
       * 字典响应数据转换器,方法签名为function(response: Object, dictMeta: DictMeta): DictData
       */
      responseConverter,
      labelField: 'label',
      valueField: 'value',
    },
  },
  /**
   * 默认标签字段
   */
  DEFAULT_LABEL_FIELDS: ['label', 'name', 'title'],
  /**
   * 默认值字段
   */
  DEFAULT_VALUE_FIELDS: ['value', 'id', 'uid', 'key'],
}

/**
 * 映射字典
 * @param {Object} response 字典数据
 * @param {DictMeta} dictMeta 字典元数据
 * @returns {DictData}
 */
function responseConverter(response, dictMeta) {
  const dicts = response.content instanceof Array ? response.content : response
  if (dicts === undefined) {
    console.warn(`no dict data of "${dictMeta.type}" found in the response`)
    return []
  }
  return dicts.map(d => dictConverter(d, dictMeta))
}

export function mergeOptions(src) {
  mergeRecursive(options, src)
}

export default options

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
Vue 3 ,如果要使用若依 Vue 2 的数据字典功能,你需要先将若依 Vue 2 的数据字典组件迁移到 Vue 3 。 具体步骤如下: 1. 安装 `@vue/composition-api` 包。 ``` npm install @vue/composition-api ``` 2. 在 Vue 3 的入口文件注册 Composition API。 ```javascript import { createApp } from 'vue' import { setup } from '@vue/composition-api' const app = createApp({}) app.use(setup) ``` 3. 将若依 Vue 2 的数据字典组件迁移到 Vue 3 。 在 Vue 3 ,数据字典组件可以使用 Composition API 实现。你可以使用 `reactive` 函数创建响应式对象,使用 `computed` 函数创建计算属性,使用 `watchEffect` 函数监听变量变化并触发相应的行为。 下面是一个简单的例子: ```javascript <template> <div> <el-select v-model="selected"> <el-option v-for="option in options" :key="option.value" :label="option.label" :value="option.value" /> </el-select> </div> </template> <script> import { reactive, computed, watchEffect } from '@vue/composition-api' import { getDicts } from '@/api/system/dict/data' export default { props: { type: { type: String, required: true }, value: { type: [String, Number], default: '' } }, setup(props, context) { const state = reactive({ options: [], selected: props.value }) const dicts = computed(() => { return getDicts(props.type) }) watchEffect(() => { state.options = dicts.value }) return { state } } } </script> ``` 上面的代码,我们使用 `reactive` 函数创建了一个响应式对象 `state`,包含了数据字典组件的状态。我们使用 `computed` 函数创建了一个计算属性 `dicts`,该计算属性会根据 `props.type` 获取对应的数据字典项。我们使用 `watchEffect` 函数监听 `dicts` 变化,并将变化后的值赋值给 `state.options`。 最后,我们将 `state` 对象返回给组件模板,以便在模板使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值