此文章属于ruoyi项目实战系列

使用目的

  1. 什么是字典数据:具体的值(0,1,"Y","N"),对应具体的业务逻辑("男","女","是","否")。
  2. 字典数据不应该只写死在代码中,还应存入数据库,通过管理系统来增删改查。

源码分析

ruoyi项目在低于3.7.0的版本中,前端字典功能实现比较简单,每个index.vue页面都请求dict的api,获取数据再加工显示即可。3.7.0之后的版本使用了混入,所以复杂了一些。

分析

  1. 入口:查看全局入口文件main.jsDictData.install()是字典功能的入口位置。

    1. function install() {
    2. Vue.use(DataDict, {//额外参数
    3. metas: {
    4. '*': {
    5. labelField: 'dictLabel',
    6. valueField: 'dictValue',
    7. request(dictMeta) {
    8. return getDicts(dictMeta.type).then(res => res.data)
    9. },
    10. },
    11. },
    12. })
    13. }

    install全局注册了一个插件DataDict,同时传入了额外参数{meta:xxx},目的是将DataDict插件对应的参数进行赋值。

  2. DataDict插件:因为该插件本身是个function,所以Vue.use会直接将function视为install()方法执行。

    1. export default function (Vue, options) {
    2. mergeOptions(options)
    3. Vue.mixin({...})
    4. }

    首先执行mergeOptions(options),目的是将传入的额外参数与DictOptions合并。具体实现是通过递归调用mergeRecursive(source,target),将DictOptions的属性覆盖或者添加。

    其次注册全局混入 Vue.mixin ,给所有 Vue 实例添加了 data()created() 方法。

    1. Vue.mixin({
    2. data(){
    3. const dict = new Dict()
    4. dict.owner = this
    5. return {dict}
    6. },
    7. created(){
    8. ....
    9. this.dict.init(this.$options.dicts).then(()=>{...})
    10. }
    11. })

    data (): 每个 Vue 页面创建一个 Dict。

    created(): 调用Dict.init(dicts)方法,传入每个vue页面声明的dicts数组(例如 dicts['sys_normal_disable'])。(额外补充:init().then(....)里的方法个人认为是为了拓展性,因为我全局查找也没有看到任何地方用到。)

  3. Dict. init () : 看注释即可

    1. init(options) {
    2. if (options instanceof Array) {
    3. //此处传进来的是每个index.vue的dicts属性,基本上是['dictName1','dictName2']之类的。
    4. options = {types: options}
    5. }
    6. const opts = mergeRecursive(DEFAULT_DICT_OPTIONS, options)//options与DEFAULT合并,并且将合并结果赋值给opts
    7. if (opts.types === undefined) {
    8. throw new Error('need dict types')
    9. }
    10. const ps = []
    11. this._dictMetas = opts.types.map(t => DictMeta.parse(t)) //调用parse,将数组中的字符串转换为DictMeta对象返回。
    12. this._dictMetas.forEach(dictMeta => {
    13. const type = dictMeta.type
    14. Vue.set(this.label, type, {})//dict.label添加属性 dictName:{}
    15. Vue.set(this.type, type, [])//dict.type 添加属性 dictName[]
    16. if (dictMeta.lazy) {
    17. return
    18. }
    19. ps.push(loadDict(this, dictMeta))
    20. })loadDict:请求后端api,将数据组装进dict
    21. return Promise.all(ps)
    22. }

简单通过注释解释一下init里的一些调用函数源码

  1. DictMeta.parse

    1. DictMeta.parse= function(options) {
    2. let opts = null
    3. if (typeof options === 'string') {
    4. opts = DictOptions.metas[options] || {}
    5. opts.type = options//opt{type:'字典名称'}
    6. } else if (typeof options === 'object') {
    7. opts = options
    8. }
    9. //创建{type:'字典名称"}并且赋值给DictOptions.meta属性
    10. opts = mergeRecursive(DictOptions.metas['*'], opts)
    11. //构造dictmeta原数据
    12. return new DictMeta(opts)
    13. }

    主要将vue页面的dicts数组以及DictOption的meta数据在整合赋值到DictMeta对象,方便后续调用。

  2. loadDict(dict,dictMeta)

    1. function loadDict(dict, dictMeta) {
    2. return dictMeta.request(dictMeta)//请求后端api,获取字典数据
    3. .then(response => {
    4. const type = dictMeta.type
    5. let dicts = dictMeta.responseConverter(response, dictMeta)//将response转换成DictData
    6. if (!(dicts instanceof Array)) {
    7. console.error('the return of responseConverter must be Array.<DictData>')
    8. dicts = []
    9. } else if (dicts.filter(d => d instanceof DictData).length !==
    10. dicts.length) {
    11. console.error('the type of elements in dicts must be DictData')
    12. dicts = []
    13. }
    14. //将response的数据插入到dict.type['dictName']的数组中
    15. //splice实现了响应式改变数组元素,所以这里不用vue.set
    16. dict.type[type].splice(0, Number.MAX_SAFE_INTEGER, ...dicts)
    17. //将dicts(也就是dictData)赋值给dict.type[type]
    18. dicts.forEach(d => {
    19. Vue.set(dict.label[type], d.value, d.label)
    20. //dict.label{'dictName':{}}添加属性d.value:d.label
    21. })
    22. return dicts
    23. })
    24. }
  3. 具体页面应用

    例如job/index.vue,

    1. <el-select v-model="queryParams.status" placeholder="请选择任务状态" clearable>
    2. <el-option
    3. v-for="dict in dict.type.sys_job_status"
    4. :key="dict.value"
    5. :label="dict.label"
    6. :value="dict.value"
    7. />
    8. </el-select>
    9. export default{
    10. dicts:['sys_job_group','sys_job_status'],
    11. //dict:{'sys_job_group':[data1,data2],'sys_job_status':[data1,data2]} 通过上文的代码全局混入得到
    12. }

Ruoyi字典源码学习的更多相关文章

  1. Aspects 源码学习

    AOP 面向切面编程,在对于埋点.日志记录等操作来说是一个很好的解决方案.而 Aspects 是一个对于AOP编程的一个优雅的实现,也可以直接借助这个库来使用AOP思想.需要值得注意的是,Aspect ...

  2. Redis源码学习:Lua脚本

    Redis源码学习:Lua脚本 1.Sublime Text配置 我是在Win7下,用Sublime Text + Cygwin开发的,配置方法请参考<Sublime Text 3下C/C++开 ...

  3. threadpool源码学习

    threadpool源码学习 __all__ = [ 'makeRequests', 'NoResultsPending', 'NoWorkersAvailable', 'ThreadPool', ' ...

  4. Asp.NetCore源码学习[2-1]:配置[Configuration]

    Asp.NetCore源码学习[2-1]:配置[Configuration] 在Asp. NetCore中,配置系统支持不同的配置源(文件.环境变量等),虽然有多种的配置源,但是最终提供给系统使用的只 ...

  5. Asp.NetCore源码学习[2-1]:日志

    Asp.NetCore源码学习[2-1]:日志 在一个系统中,日志是不可或缺的部分.对于.net而言有许多成熟的日志框架,包括Log4Net.NLog.Serilog 等等.你可以在系统中直接使用这些 ...

  6. [阿里DIN]从论文源码学习 之 embedding_lookup

    [阿里DIN]从论文源码学习 之 embedding_lookup 目录 [阿里DIN]从论文源码学习 之 embedding_lookup 0x00 摘要 0x01 DIN代码 1.1 Embedd ...

  7. [阿里DIN] 从论文源码学习 之 embedding层如何自动更新

    [阿里DIN] 从论文源码学习 之 embedding层如何自动更新 目录 [阿里DIN] 从论文源码学习 之 embedding层如何自动更新 0x00 摘要 0x01 DIN源码 1.1 问题 1 ...

  8. [数据结构1.2-线性表] 动态数组ArrayList(.NET源码学习)

    [数据结构1.2-线性表] 动态数组ArrayList(.NET源码学习) 在C#中,存在常见的九种集合类型:动态数组ArrayList.列表List.排序列表SortedList.哈希表HashTa ...

  9. [算法2-数组与字符串的查找与匹配] (.NET源码学习)

    [算法2-数组与字符串的查找与匹配] (.NET源码学习) 关键词:1. 数组查找(算法)   2. 字符串查找(算法)   3. C#中的String(源码)   4. 特性Attribute 与内 ...

随机推荐

  1. [USACO 2009 Mar S]Look Up_via牛客网

    题目 链接:https://ac.nowcoder.com/acm/contest/28537/N 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言 ...

  2. mysql查询版本

    系统环境下 :mysql -V; mysql内:select version();

  3. 一文搞懂│php 中的 DI 依赖注入

    目录 什么是 DI / 依赖注入 依赖注入出现的原因 简单的依赖注入 高阶的依赖注入 依赖注入的应用 依赖注入高阶优化 什么是 DI / 依赖注入 依赖注入DI 其实本质上是指对类的依赖通过构造器完成 ...

  4. 如何在BI中增加“路线地图”并进行数据分析?

    随着客户的需求越来越"百变",最近在做大屏设计的葡萄陷入了困境. 近期客户提出的需求是想在BI工具中增加 "路线地图"展示功能并进行数据分析. 不仅如此,这个& ...

  5. CF708C Centroids(树形DP)

    发现变重心就是往重心上割,所以\(\text{up and down}\),一遍统计子树最大\(size\),一遍最优割子树,\(down\),\(up\)出信息,最后\(DFS\)出可行解 #inc ...

  6. java学习第五天异常机制.day14

    异常处理机制 确保程序的正常执行.这种机制称为异常处理机制 异常对象 常用方法 方法介绍 toString 返回异常类型和异常信息 getMessage 返回异常信息 printStackTrace ...

  7. scratch制作彩虹猫病毒模拟器

    scratch制作彩虹猫病毒模拟器 hello,大家好. 编程慢慢更加接近生活,甚至小孩也开始学了,比如scratch编程,小编今天就带了一件作品(彩虹猫病毒模拟器) 我们先看一下效果| 做的还可以, ...

  8. ABC 203 F - Weed (DP)

    ABC203F - Weed 题意转述 S t e v e \rm Steve Steve 和 A l e x \rm Alex Alex 正在下界( N e t h e r l e n d \rm ...

  9. 「学习笔记」斜率优化dp

    目录 算法 例题 任务安排 题意 思路 代码 [SDOI2012]任务安排 题意 思路 代码 任务安排 再改 题意 思路 练习题 [HNOI2008]玩具装箱 思路 代码 [APIO2010]特别行动 ...

  10. 最短路径算法-迪杰斯特拉(Dijkstra)算法在c#中的实现和生产应用

    迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先遍历思想),直到扩展到终点为止 贪心算法(Greedy ...