• 若依vue中字典Dict插件的研究


    涉及的知识点

    插件与组件的区别

    Vue组件(component)用来构成你的App的业务模块,它的目标是App.vue。
    Vue插件(plugin) 用来增强你的技术栈的功能模块, 它的目标是Vue本身。(插件是对Vue的功能的增强和补充)

    插件的作用

    插件通常用来为 Vue 添加全局功能。插件的功能范围没有严格的限制——一般有下面几种:
    添加全局方法或者属性。如: vue-custom-element
    添加全局资源:指令/过滤器/过渡等。如 vue-touch
    通过全局混入来添加一些组件选项。如 vue-router
    添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。
    一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router

    this.$options

    在这里插入图片描述
    上图中dicts的值可以通过this.$options.dicts拿到

    options的五类属性
    数据: data, props, propsData, computed, Watch;

    DOM: el, template, render, renderError;

    声明周期钩子: beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、activated、deactivated、beforeDestroy、destroyed、errorCaptured;

    资源: directives、filters、components;

    组合: parent、mixins、extends、provide、inject;

    minx

    具体自己百度

    开发插件

    Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:

    MyPlugin.install = function (Vue, options) {
      // 1. 添加全局方法或 property
      Vue.myGlobalMethod = function () {
        // 逻辑...
      }
      // 2. 添加全局资源
      Vue.directive('my-directive', {
        bind (el, binding, vnode, oldVnode) {
          // 逻辑...
        }
        ...
      })
      // 3. 注入组件选项
      Vue.mixin({
        created: function () {
          // 逻辑...
        }
        ...
      })
      // 4. 添加实例方法
      Vue.prototype.$myMethod = function (methodOptions) {
        // 逻辑...
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    若依vue dict插件

    插件安装

    导入并使用插件DataDict,插件内部会调用的到 request(dictMeta)方法用请求管理后台

    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)方法用请求管理后台
            request(dictMeta) {
            // 请求后端接口:根据字典类型查询字典数据信息
              return getDicts(dictMeta.type).then(res => res.data)
            },
          },
        },
      })
    }
    
    export default {
      install,
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在main.js里面会执行:

    DictData.install()

    插件定义

    this.dict.init(this.$options.dicts)

    是比较关键的步骤:this.dict.init(this.$options.dicts) 将vue页面上定义的dicts数组传进去,组装数据,请求后端,获取对应字典数据

    options和this.$options的差别

    options

    定义插件的时候传入的值
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    this.$options

    在这里插入图片描述
    上图中dicts的值可以通过this.$options.dicts拿到。

    具体代码,加了一些注释,方便理解

    dict/index.js

    import Dict from './Dict'
    import { mergeOptions } from './DictOptions'
    
    /**
     * 
     * @param {*} Vue 
     * @param {*} options , 插件安装时传入的对象,我们项目里面是:
     * metas: {
         '*': {
           labelField: 'dictLabel',
           valueField: 'dictValue',
           request(dictMeta) {
           //调用后端接口获取数据
             return getDicts(dictMeta.type).then(res => res.data)
           },
         },
       },
     */
    export default function(Vue, options) {
      //mergeOptions(options)会将DictOptions的options合并
      mergeOptions(options)
      Vue.mixin({
        data() {
          //如果vue没有定义dixts即this.$options.dicts为空,则返回{}相当于不混入 
          if (this.$options === undefined || this.$options.dicts === undefined || this.$options.dicts === null) {
            return {}
          }
          //DataDict初始化字典数据
          const dict = new Dict()
          dict.owner = this
          return {
            //混入dict,使得页面内能用dict对象
            dict
          }
        },
        created() {
          if (!(this.dict instanceof Dict)) {
            return
          }
          options.onCreated && options.onCreated(this.dict)
          //执行Dict的init方法,将vue页面上定义的dicts数组传进去,组装数据,请求后端,获取对应字典数据
          this.dict.init(this.$options.dicts).then(() => {
            options.onReady && options.onReady(this.dict)
            this.$nextTick(() => {
            //定义了一些回调,如果有需要,可以在页面上加onDictReady 方法或者dictReady事件,可以对dict进行一些后续处理
              this.$emit('dictReady', this.dict)
              if (this.$options.methods && this.$options.methods.onDictReady instanceof Function) {
                this.$options.methods.onDictReady.call(this, this.dict)
              }
            })
          })
        },
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    dict/DictOptions.js

    import { mergeRecursive } from "@/utils/ruoyi";
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    Dict.js

    比较关键的是loadDict(dict, dictMeta)来查询后端,dictMeta.request(dictMeta)用的比较灵活,dictMeta是插件安装的时候写的option

    import Vue from 'vue'
    import { mergeRecursive } from "@/utils/ruoyi";
    import DictMeta from './DictMeta'
    import DictData from './DictData'
    
    const DEFAULT_DICT_OPTIONS = {
      types: [],
    }
    
    /**
     * @classdesc 字典
     * @property {Object} label 标签对象,内部属性名为字典类型名称
     * @property {Object} dict 字段数组,内部属性名为字典类型名称
     * @property {Array.} _dictMetas 字典元数据数组
     */
    export default class Dict {
      constructor() {
        this.owner = null
        this.label = {}
        this.type = {}
      }
    //这里接收的是:this.$options.dicts
      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) {
    //比较灵活,dictMeta是插件定义的时候传入的option
      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.')
            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
        })
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84

    后续

    如果有需要,可以在页面上加onDictReady 方法或者dictReady事件,可以对dict进行一些后续处理

  • 相关阅读:
    《单片机》期末考试复习-学习笔记总结
    电影产业的数据洞察:爬虫技术在票房分析中的应用
    通过Gunicorn、Supervisor和Nginx更好地运行Django
    React基础教程:TodoList案例
    【623. 在二叉树中增加一行】
    JVM 方法区
    python实现炫酷的屏幕保护程序
    串的匹配 (KPM算法)
    50天50个前端小项目(纯html+css+js)第十八天(背景轮播图)
    stata17中java installation not found或java not recognozed的问题
  • 原文地址:https://blog.csdn.net/qq_27575627/article/details/126766383