Ruoyi字典源碼學習

此文章屬于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 = thisreturn {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合并,并且將合并結果賦值給optsif (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.typeVue.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,將數據組裝進dictreturn Promise.all(ps)}
簡單通過注釋解釋一下init里的一些調用函數源碼
  1. DictMeta.parse
    DictMeta.parse= function(options) {let opts = nullif (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.typelet dicts = dictMeta.responseConverter(response, dictMeta)//將response轉換成DictDataif (!(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.setdict.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-optionv-for="dict in dict.type.sys_job_status":key="dict.value":label="dict.label":value="https://www.huyubaike.com/biancheng/dict.value"/></el-select> export default{dicts:['sys_job_group','sys_job_status'],//dict:{'sys_job_group':[data1,data2],'sys_job_status':[data1,data2]} 通過上文的代碼全局混入得到}

    推薦閱讀