当前位置:首页 > 技术 > 正文内容

Ruoyi字典源码学习

Lotus2022-10-07 11:00技术

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

使用目的

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

源码分析

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

分析

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

    function install() {
      Vue.use(DataDict, {//额外参数
        metas: {
          '*': {
            labelField: 'dictLabel',
            valueField: 'dictValue',
            request(dictMeta) {
              return getDicts(dictMeta.type).then(res => res.data)
            },
          },
        },
      })
    }
    

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

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

    export default function (Vue, options) {
    	mergeOptions(options)
    	Vue.mixin({...})
    }
    

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

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

    Vue.mixin({
    	data(){
    		const dict = new Dict()
    		dict.owner = this
    		return {dict}
    	},
    	created(){
    	....
    	this.dict.init(this.$options.dicts).then(()=>{...})
    	}
    	
    })
    

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

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

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

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

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

  1. DictMeta.parse

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

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

  2. loadDict(dict,dictMeta)

    function loadDict(dict, dictMeta) {  
      return dictMeta.request(dictMeta)//请求后端api,获取字典数据  
        .then(response => {  
          const type = dictMeta.type  
          let dicts = dictMeta.responseConverter(response, dictMeta)//将response转换成DictData  
          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 = []  
          }  
          //将response的数据插入到dict.type['dictName']的数组中  
          //splice实现了响应式改变数组元素,所以这里不用vue.set  
          dict.type[type].splice(0, Number.MAX_SAFE_INTEGER, ...dicts)
          //将dicts(也就是dictData)赋值给dict.type[type]  
          dicts.forEach(d => {  
            Vue.set(dict.label[type], d.value, d.label)
            //dict.label{'dictName':{}}添加属性d.value:d.label  
          })  
          return dicts  
        })  
    }	
    
  3. 具体页面应用
    例如job/index.vue,

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

原文链接

扫描二维码推送至手机访问。

版权声明:本文来源于网络,仅供学习,如侵权请联系站长删除。

本文链接:https://news.layui.org.cn/post/355.html

分享给朋友:

“Ruoyi字典源码学习” 的相关文章

Python 3.12 目标:还可以更快!

按照发布计划,Python 3.11.0 将于 2022 年 10 月 24 日发布。 据测试,3.11 相比于 3.10,将会有 10-60% 的性能提升,这个成果主要归功于“Faster CPython”项目,即“香农计划”。 关于“香农计划”的详情,可查看 Python 之父的主题分享,以及他的一则播客访谈。 3.11 版本为 Python 的提速开了一个激动人心的好头。接下来,3.12 还...

TTD 专题 (第一篇):C# 那些短命线程都在干什么?

一:背景 1.讲故事 在分析的众多dump中,经常会遇到各种奇葩的问题,仅通过dump这种快照形式还是有很多问题搞不定,而通过 perfview 这种粒度又太粗,很难找到问题之所在,真的很头疼,比如本篇的 短命线程 问题,参考图如下: 我们在 t2 时刻抓取的dump对查看 短命线程 毫无帮助,我根本就不知道这个线程生前执行了什么代码,为什么这么短命,还就因为这样的短命让 线程池 的线程暴增。...

路由基础之中级网络工程师企业网络架构BGP​

路由基础之中级网络工程师企业网络架构BGP​ 原理概述:​ 防火墙(英语:Firewall)技术是通过有机结合各类用于安全管理与筛选的软件和硬件设备,帮助计算机网络于其内、外网之间构建一道相对隔绝的保护屏障,以保护用户资料与信息安全性的一种技术。​ 防火墙技术的功能主要在于及时发现并处理计算机网络运行时可能存在的安全风险、数据传输等问题,其中处理措施包括隔离与保护,同时可对计算机网络安全当中的各...

Python基础(九) | time random collections itertools标准库详解

⭐本专栏旨在对Python的基础语法进行详解,精炼地总结语法中的重点,详解难点,面向零基础及入门的学习者,通过专栏的学习可以熟练掌握python编程,同时为后续的数据分析,机器学习及深度学习的代码能力打下坚实的基础。 ????本文已收录于Python基础系列专栏: Python基础系列教程 欢迎订阅,持续更新。 Python自身提供了比较丰富的生态,拿来即用,可极大的提高开发效率 9...

JavaScript之无题之让人烦躁的模块化

  我怎么记得我好像写过相关类型的文章,但是我找遍了我的博客没有~那就再写一遍吧,其实模块化的核心内容也算不上是复杂,只不过需要整理一下,规划一下罢了。嘻嘻。   开始写标题的时候我就在纠结一件事情,就是,先吃喜欢吃的,还是后吃喜欢吃的,翻译过来就是我应该先写CommonJS和ES6 Module,还是先写CMD和AMD。嗯,我决定了,谁先做好了我就先吃谁。   其实模块化的缘由很简单,就一句话,...

一次服务器被入侵的处理过程分享

下文中的,给文件和目录加锁,是指给文件和目录增加了一些属性,只读等。 chattr +ia 目录 一、服务器入侵现象 二、服务器排查和处理 2.1、服务器被入侵的可能原因 2.2、排查和处理步骤 三、本次入侵需要带来启示的点 四、本次服务器被入侵的一些启示 一、服务器入侵现象 近期有一个朋友的服务器(自己做了网站)好像遭遇了入侵,具体现象是: 服务器 CPU 资源长期 1...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。