枚举值实现下拉和tag展示的组件封装(vue2+js+elementUI)

枚举值组件EnumBase(实现展示数据的时候提供tag样式,也可以变成下拉选择)
  • AllowSelect判断是要下拉选择还是展示tag标签 (所有prop要使用的时候尽量通过computed进行,避免直接修改prop值)

    <div :class="[AllowSelect?'auto-width':'']">
    	<tr-select
          v-if="AllowSelect"
          ...
        />
        <template v-else>
        ...
        </template>
    </div>
    
  • 传入的枚举数据需要处理。使用传入过滤方法或者默认方法进行过滤,将源数据转换成数组形式,然后使用数组的filter方法过滤,需确保返回结果是数组。

    Options: {
      get() {
        const defaultFilter = (value) => value
        const filterMethod = this.optionFilter ?? defaultFilter
        const sourceOptions = this.EnumData?.toArray() || []
        const filterResult = sourceOptions.filter(filterMethod)
        const filterResultIsArray = Array.isArray(filterResult)
        return filterResultIsArray ? filterResult : []
      }
    }
    
  • 对于不允许选择,存在直接展示和tag展示。tag的样式从prop传入数组中获取。 这时候需要注意label的长度来控制展示效果(getStringLength方法)

    TagStyle: {
          get() {
            let widestLabelLength = 0
            this.Options.forEach((option) => {
              const labelWidth = this.getStringLength(option.label)
              widestLabelLength = widestLabelLength < labelWidth ? labelWidth : widestLabelLength
            })
            const defaultTagWidth = `${widestLabelLength * 5 + 10}px`
            return `width:${this.tagWidth ?? defaultTagWidth};`
          }
        },
    
    EnumBase代码:
    <template>
    <tr-select v-if="AllowSelect" :data.sync="Data" :options="Options" v-bind="$attrs" width="100%" v-on="$listeners" />
      <template v-else>
        <el-tag
          v-if="UseTag && LabelVisible"
          :type="Type"
          :disable-transitions="true"
          v-bind="$attrs"
          v-on="$listeners"
        >
          <div class="tag-content" :style="TagStyle">
            <span>{{ Label }}</span>
          </div>
        </el-tag>
    
        <span v-else>{{ Label }}</span>
    
      </template>
    </div>
    
    </template> <script> import TrSelect from '@/components/Select/Select.vue'

    // #region 值转换函数

    // #endregion

    export default {
    components: {
    TrSelect
    },
    model: {
    prop: 'data',
    event: 'update:data'
    },
    props: {
    /** 绑定值 /
    data: {
    type: [String, Number, Array],
    default: undefined
    },
    /
    * 是否允许选择 /
    allowSelect: {
    type: Boolean,
    default: true
    },
    /
    * 是否使用tag装饰,仅在allowSelect为false时有效 */
    useTag: {
    type: Boolean,
    default: true
    },

      /** Tag的宽度 */
      tagWidth: {
        type: String,
        default: undefined
      },
      /** options的过滤函数 */
      optionFilter: {
        type: Function,
        default: undefined
      }
    
    },
    data() {
      return {
        myData: undefined,
        enumData: undefined,
        EnumData: undefined
      }
    },
    computed: {
      Data: {
        get() {
          return this.data ?? this.myData
        },
        set(val) {
          this.myData = val
          this.$emit('update:data', val)
        }
      },
      AllowSelect: {
        get() {
          return this.allowSelect
        }
      },
      UseTag: {
        get() {
          return !this.allowSelect && this.useTag
        }
      },
      TagStyle: {
        get() {
          let widestLabelLength = 0
          this.Options.forEach((option) => {
            const labelWidth = this.getStringLength(option.label)
            widestLabelLength = widestLabelLength < labelWidth ? labelWidth : widestLabelLength
          })
          // console.info(widestLabelLength)
          const defaultTagWidth = `${widestLabelLength * 5 + 10}px`
          return `width:${this.tagWidth ?? defaultTagWidth};`
        }
      },
      Label: {
        get() {
          // console.info(this.Data)
          // console.info(this.valueToLabel(this.Data))
          return this.valueToLabel(this.Data)
        }
      },
      LabelVisible: {
        get() {
          return this.Label !== ''
        }
      },
      Type: {
        get() {
          return this.valueToType(this.Data)
        }
      },
      Options: {
        get() {
          const defaultFilter = (value) => value
          const filterMethod = this.optionFilter ?? defaultFilter
          const sourceOptions = this.EnumData?.toArray() || []
          const filterResult = sourceOptions.filter(filterMethod)
          const filterResultIsArray = Array.isArray(filterResult)
          return filterResultIsArray ? filterResult : []
        }
      }
    },
    watch: {
      enumData: {
        deep: true,
        handler(newValue) {
          this.EnumData = newValue
        }
      },
      data: {
        handler(value) {
          this.myData = value
        }
      }
    },
    mounted() {
    
    },
    methods: {
    
      valueToLabel(value) {
        // console.info(this.EnumData)
        const label = this.EnumData?.getItemByValue(value)?.label || ''
        return label
      },
    
      valueToType(value) {
        const type = this.EnumData?.getItemByValue(value)?.type || ''
        return type
      },
    
      getStringLength(str) {
        if (str === undefined) { return 0 }
        const chineseCharacterLength = 2
        const englishCharacterLength = 1
        const chinese = str.match(/[\u4e00-\u9fa5]/g)
        const chineseCount = chinese ? chinese.length : 0
        const englishCount = str.length - chineseCount
        return chineseCount * chineseCharacterLength + englishCount * englishCharacterLength
      }
    
    }
    

    }
    </script>

    <style lang="scss" scoped> .tag-content { display: flex; justify-content: center; } </style>
TrSelect封装
TrSelect代码
<template>
  <div class="tr-select" :style="WidthStyle">
    <el-select
      ref="selectRef"
      v-model="Data"
      v-bind="$attrs"
      :filterable="Filterable"
      :remote="remote"
      :placeholder="placeholder || $t('qing-xuan-ze')"
      :remote-method="remoteSearch"
      :loading="loading"
      :clearable="clearable"
      :multiple="multiple"
      :collapse-tags="true"
      :disabled="disabled"
      :default-first-option="true"
      style="width: 100%"
      @focus="handleFocus"
      @change="handleChange"
      @remove-tag="handleRemoveTag"
      @clear="handleClear"
      @blur="handleBlur"
    >
      <el-option
        v-for="(opt, index) in Options"
        :key="index"
        :label="opt.label"
        :value="opt.value"
        :disabled="opt.disabled || false"
      />
    </el-select>
  </div>
</template>

<script>

export default {
  name: 'TrSelect',
  components: {},
  model: {
    prop: 'data',
    event: 'update:data'
  },
  props: {
    data: {
      type: [String, Number, Array],
      default: ''
    },
    /**
     * getDataFunction(done,data,searchWord)
     * 当调用done(newOptions)时,会把newOptions内的选项传递给组件
     * 当设置remote为True时,用户输入的内容会随searchWord传递
     * 为了能够解决远程搜索的反显问题,当remote为true时,会把当前组件绑定的data也传递进去
     * 这样可以通过该参数搜索后台,并进行反显
     * */
    getDataFunction: {
      type: Function,
      default: undefined
    },
    /** 设置默认的选项,该选项不会被getDataFunction传递的选项覆盖 */
    options: {
      type: Array,
      default: () => [
        // {
        //   label: '选项1',
        //   value: 1
        // },
        // {
        //   label: '选项2',
        //   value: 2
        // },
        // {
        //   label: '选项3',
        //   value: 3
        // }
      ]
    },
    /**
     * 刷新选项的方式: 1:created时刷新(默认值) 2.mounted时刷新 4.focus时刷新 8.refreshFlag更改时触发
     * 可以任意组合上述四项,例如传递3,代表了created和mounted时会刷新,传递5,代表了created和focus时会刷新
     */
    refreshMode: {
      type: Number,
      default: 1
    },
    /** 使用deepWatch监听 */
    refreshFlag: {
      type: [Boolean, String, Object, Array, Number],
      default: undefined
    },
    refreshDeepWatch: {
      type: Boolean,
      default: false
    },
    /** 是否自动选中选项中的第一项,优先级低于其他选中配置 */
    autoSelect: {
      type: Boolean,
      default: false
    },
    autoSelectFirstOne: {
      type: Boolean,
      default: false
    },
    /** 是否根据label值默认选中选项 */
    defaultSelectByLabel: {
      type: [String, Number, Array],
      default: undefined
    },
    /** 是否根据value值默认选中选项 */
    defaultSelectByValue: {
      type: [String, Number, Array],
      default: undefined
    },
    /** 可以通过'100px'设定固定宽度,也可以通过'100%'设置百分比宽度,默认值为240px,与el-select一致*/
    width: {
      type: String,
      default: undefined
    },
    placeholder: {
      type: String,
      default: undefined
    },
    /** 需要过滤时设为true */
    filterable: {
      type: Boolean,
      default: false
    },
    /** 需要启用远程功能时,设为true */
    remote: {
      type: Boolean,
      default: false
    },
    /** 当用户输入完内容后,间隔多久后开始调用getDataFunction,单位毫秒 */
    remoteDelay: {
      type: Number,
      default: 300
    },
    /** 请勿在这里传递,该属性仅仅起到阻断作用 */
    remoteMethod: {
      type: Function,
      default: undefined
    },
    /** 远程搜索是否允许空的字符串 */
    remoteSearhAllowEmptyString: {
      type: Boolean,
      default: false
    },
    /** 是否可清除 */
    clearable: {
      type: Boolean,
      default: true
    },
    /** 是否多选 */
    multiple: {
      type: Boolean,
      default: false
    },
    /** 是否不可更改 */
    disabled: {
      type: Boolean,
      default: false
    },
    /** 当前选择的内容的全部数据 */
    currentSelect: {
      type: [Array, String, Object, Number, Boolean],
      default: undefined
    }
  },
  data() {
    return {
      loading: false,
      myOptions: [],
      remoteSearchKeyword: undefined,
      myRemoteTask: null,
      myOptionsDictionary: {},
      disabledWatchEmit: false
    }
  },
  computed: {
    Data: {
      get() {
        return this.data
      },
      set(val) {
        // console.info('update:data', val)
        this.$emit('update:currentSelect', this.myOptionsDictionary[val])
        this.$emit('update:data', val)
        this.$emit('change', val)
        this.disabledWatchEmit = true
        setTimeout(() => {
          this.disabledWatchEmit = false
        }, 200)
        // console.info(this.myOptionsDictionary)

        // console.info('设置了', val)
      }
    },
    Options: {
      get() {
        var temp = []
        // 合并默认选项
        if (typeof this.options === 'object') {
          Object.assign(temp, this.options)
        }
        // 合并远程选项
        Object.assign(temp, this.myOptions)

        // 建立value和项对应的字典
        // eslint-disable-next-line vue/no-side-effects-in-computed-properties
        this.myOptionsDictionary = {}
        Object.keys(temp).forEach((key) => {
          this.myOptionsDictionary[temp[key].value] = temp[key]
        })
        return temp
      },
      set(val) {
        if (typeof val === 'object') {
          this.myOptions = val
          // 通过访get方法,建立字典,下一行不可删除
          var test = this.Options
        }
      }
    },
    RefreshWhenCreated: {
      get() {
        return (this.refreshMode & 1) === 1
      }
    },
    RefreshWhenMounted: {
      get() {
        return (this.refreshMode & 2) === 2
      }
    },
    RefreshWhenFocus: {
      get() {
        // console.info('计算')
        // console.info(this.refreshMode)
        // console.info(this.refreshMode & 4)
        return (this.refreshMode & 4) === 4
      }
    },
    RefreshWhenRefreshFlagChange: {
      get() {
        return (this.refreshMode & 8) === 8
      }
    },
    Filterable: {
      get() {
        // 当启用了远程搜索时,直接返回true,否则返回filterable
        if (this.remote === true) {
          return true
        } else {
          return this.filterable
        }
      }
    },
    WidthStyle: {
      get() {
        if (this.width === undefined) {
          return 'display:inline-block;position:relative;'
        } else {
          return `width:${this.width};`
        }
      }
    }
  },
  watch: {
    refreshFlag: {
      deep: true,
      handler(newValue, oldValue) {
        if (newValue === undefined) {
          return
        }
        // 在调用之前,需要将loading重置,否则不会重新刷新方法
        this.loading = false
        this.refreshOptions()
      },
      immediate: false
    },
    Options: {
      deep: true,
      handler(newValue, oldValue) {
        // 当选项更改时,要考虑绑定值是否与选项相契合,如果绑定值为空,则要考虑自动选中
        if ([undefined, null, ''].includes(this.Data)) {
          setTimeout(() => {
            this.doAutoSelect(newValue)
          }, 10)
        } else {
          this.fitCurrentValue(newValue)
        }
      }
    },
    Data: {
      handler(value) {
        if (this.disabledWatchEmit) return

        this.$emit('change', value)
      }
    }
  },
  created() {
    if (this.RefreshWhenCreated) {
      this.refreshOptions()
    }
  },
  mounted() {
    if (this.RefreshWhenMounted) {
      this.refreshOptions()
    }
    // console.info(this.$listeners)
  },
  methods: {
    /** 远程搜索,防抖 */
    remoteSearch(keyword) {
      // console.info(keyword)
      if ([undefined, null].includes(keyword)) {
        return
      }
      if (typeof keyword !== 'string') {
        return
      }
      const word = keyword.trim()
      if (word === '' && !this.remoteSearhAllowEmptyString) {
        return
      }

      // 取消掉之前的任务
      if (this.myRemoteTask !== null) {
        clearTimeout(this.myRemoteTask)
      }
      // 清空绑定值

      // 重新建立新任务
      this.myRemoteTask = setTimeout(() => {
        this.refreshOptions(keyword)
        this.myRemoteTask = null
      }, this.remoteDelay)
    },
    /** 刷新选项 */
    refreshOptions(keyword) {
      if (!this.loading) {
        // debugger
        this.loading = true
        var value = null
        if (this.remote) {
          value = JSON.parse(JSON.stringify(this.Data))
        }
        // //console.info(typeof (this.getDataFunction))
        // //console.info(12)
        if (
          this.getDataFunction !== undefined &&
          typeof this.getDataFunction === 'function'
        ) {
          this.getDataFunction(this.appendOptions, value, keyword)
        } else {
          this.loading = false
        }
      }
    },
    /** 添加远程搜索的选项 */
    appendOptions(newOptions) {
      if (this.loading) {
        // debugger
        this.loading = false
        this.Options = newOptions
      }
    },
    /** 绑定值更改 */
    handleChange(data) {
      // console.info(this.myOptionsDictionary)
      // console.info(data)

    },
    /** 被聚焦 */
    handleFocus() {
      if (this.RefreshWhenFocus) {
        // console.info(11)
        this.refreshOptions()
      }
      this.$emit('focus')
    },
    /** 多选项被移除 */
    handleRemoveTag(value) {
      this.$emit('removeTag', value)
    },
    /** 绑定值被清除 */
    handleClear() {
      // this.$emit('update:currentSelect', undefined)
      this.$emit('clear')
    },
    /** 组件失去焦点 */
    handleBlur(event) {
      // console.info('失去焦点')
      // console.info(event)
      this.$emit('blur', event)
    },
    /**  */
    fitCurrentValue(newOptions) {
      newOptions.forEach((opt) => {
        if (opt.value === this.Data) {
          this.Data = opt.value
        }
      })
    },
    /** 执行自动选择 */
    doAutoSelect(newOptions) {
      // 只有一个选项时,默认选中,和有多个选项时,默认选中第一个是相同的
      // 如果指定了选择的标准(按照value值或者按照label值,优先级value大于label,),则按照标准进行选择
      // 选择了后要触发值更改事件
      // console.info('执行自动选择')
      // const newOptions = this.Options
      const valueList = []
      const labelList = []

      if (this.autoSelectFirstOne && newOptions.length >= 1) {
        valueList.push(newOptions[0].value)
      }

      try {
        // 考虑value选中(单选时优先级高于label)
        // 考虑label选中
        // 考虑第一项自动选中,优先级最低

        // 遍历选项,根据条件找到所有的满足条件的项
        newOptions.forEach((opt) => {
          if (this.defaultSelectByValue !== undefined) {
            if (
              ['string', 'number'].includes(typeof this.defaultSelectByValue)
            ) {
              // 简单类型
              if (this.defaultSelectByValue === opt.value) {
                valueList.push(opt.value)
              }
            } else if (this.defaultSelectByValue instanceof Array) {
              // 数组类型
              if (this.defaultSelectByValue.includes(opt.value)) {
                valueList.push(opt.value)
              }
            }
          }

          if (this.defaultSelectByLabel !== undefined) {
            if (['string', 'number'].includes(typeof (this.defaultSelectByLabel))) {
              // 简单类型
              if (this.defaultSelectByLabel === opt.label) {
                labelList.push(opt.value)
              }
            } else if (this.defaultSelectByLabel instanceof Array) {
              // 数组类型
              if (this.defaultSelectByLabel.includes(opt.label)) {
                labelList.push(opt.value)
              }
            }
          }
        })

        const a = new Set(labelList)
        const b = new Set(valueList)
        const multiSelect = Array.from(new Set([...a, ...b]))
        const multiData = multiSelect.length >= 1 ? multiSelect : ''
        const firstValue = newOptions.length === 1 ? [newOptions[0].value] : []
        const singleSelect = [].concat(firstValue, labelList, valueList)
        const singleData =
          singleSelect.length >= 1 ? singleSelect[singleSelect.length - 1] : ''
        const newData = this.multiple === true ? multiData : singleData

        // 设置值
        if (newData !== '') {
          this.Data = newData
          this.$refs.selectRef.$emit('change', newData)
          this.$refs.selectRef.blur()
        }
      } catch (err) {
        console.error(err)
      }
    },
    clearOptions() {
      this.Options = []
    }
  }
}
</script>

<style lang="scss" scoped>

</style>
使用方法:
定义js文件
import { EsEnum } from '@/components/utils'

export const LogsType = new EsEnum([
  {
    code: 'ESign',
    value: 1,
    label: '电子签名',
    type: 'success'
  },
  {
    code: 'User',
    label: '用户操作,
    type: 'primary'
  }

])
定义vue文件
<script>
import EnumBase from '@/components/Template/EnumBase'
import { LogsType } from './LogsType.js'

export default {
  extends: EnumBase,
  created() {
    this.enumData = LogsType
  }
}
</script>
EsEnum方法的封装
// #region 名称转换
/**
 * 函数将name转换为 camelCase, CamelCase, kebab-case 的形式
 * @param name: 待格式化的名称
 * @param pattern: 模式,若传入number类型,则camelCase为1,其余按顺序递增
 */
export function NameFormat(name, pattern) {
  const patternRange = ['camelCase', 'CamelCase', 'kebab-case']
  let selectedPattern = null
  if (typeof pattern === 'number') {
    let index = pattern < 1 ? 1 : pattern
    index = index > patternRange.length ? patternRange.length : index
    selectedPattern = patternRange[index - 1]
  } else {
    if (patternRange.indexOf(pattern) === -1) {
      selectedPattern = patternRange[0]
    } else {
      selectedPattern = pattern
    }
  }
  switch (selectedPattern) {
    case 'camelCase':
      return camelCase(name)
    case 'CamelCase':
      return CamelCase(name)
    case 'kebab-case':
      return kebabCase(name)
  }
}

/**
     * 将输入的字符串转换为kebab-case
     * @param str 输入的字符串
     * @returns 转换后的结果
     */
function kebabCase(str) {
  return str
    .replace(/([^A-Za-z0-9]+)/g, '-') // 任意非数字字母的连续字符 => -
    .replace(/^([0-9-]+)([a-zA-Z])/g, '$2') // 去掉单词前的所有非字母字符
    .replace(/([a-zA-z0-9])(-?)$/g, '$1') // 去掉单词后的所有非字母、非数字字符
    .replace(/([a-z])([A-Z])/g, '$1-$2')// aA=>a-A
    .replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')// AAAa=>AA-Aa
    .replace(/([0-9])([a-zA-Z])/g, '$1-$2') // V9a=>V9-a
    .toLowerCase()
}
/**
     * 将输入的字符串转为CamelCase
     * @param str 输入的字符串
     * @returns 转换后的结果
     */
function CamelCase(str) {
  return kebabCase(str)
    .replace(/(.)/, '-$1')
    .replace(/(-[a-z])/g, (str) => str[1].toUpperCase())
}
/**
     * 将输入的字符串转为camelCase
     * @param str 输入的字符串
     * @returns 转换后的结果
     */
function camelCase(str) {
  return CamelCase(str)
    .replace(/(.)/, (str) => str.toLowerCase())
}

// const testData = ['goodMorning', 'GoodMorning', '-458---goodMorning....', 'good--Morning', 'goodMORNINGEveryday']
// for (const str of testData) {
//   console.log(str)
//   console.log(kebabCase(str))
//   console.log(CamelCase(str))
//   console.log(camelCase(str))
//   console.log('')
// }

// #endregion

/**
 * 该函数考虑expression和method(params)
 * @param {*} expression 返回布尔值的表达式
 * @param {*} valueDefault 默认值
 * @param {Function} method 返回布尔值的函数
 * @param {Object|Array} params 函数的入参
 * @returns
 */
export function BoolValueHandle(expression, valueDefault, method, params) {
  if (method === undefined) {
    if (expression === undefined) {
      return valueDefault
    } else {
      return expression
    }
  } else {
    var temp = method(params)
    if (temp !== undefined && typeof (temp) === 'boolean') {
      return temp
    } else {
      console.warn('方法应该返回boolean类型的值')
      if (expression === undefined) {
        return valueDefault
      } else {
        return expression
      }
    }
  }
}

/**
 * 该函数将考虑valueOrFunction的类型是function还是其他。
 * 为undefined,返回 valueDefault;
 * 为function时,返回 function(params) ?? valueDefault
 * 其他情况,返回  value
 * @param {*} valueOrFunction 值或者函数
 * @param {*} valueDefault 值或函数为undefined时的默认值
 * @param {*} params 传递给函数的参数
 * @returns
 */
export function ValueHandle(valueOrFunction, valueDefault, params) {
  // console.info(valueOrFunction)
  if (valueOrFunction === undefined) {
    return valueDefault
  }

  if (typeof valueOrFunction !== 'function') {
    const value = valueOrFunction
    return value
  }
  // console.info(valueOrFunction)
  const method = valueOrFunction
  const methodReturns = method(params)
  // console.info(methodReturns)
  return methodReturns ?? valueDefault
}

/**
 * 生成枚举型的Object
 * @param {*} arr 枚举的设定值。例如[['red',0],['green',1]],最终可以通过.red .green获得对应值0 和 1
 * @returns 枚举型
 */
export function MakeEnum(arr) {
  const obj = {}
  if (!Array.isArray(arr)) {
    throw new Error('arr 不是 Array')
  }
  arr.forEach((element, index) => {
    if (typeof element !== 'object' && typeof element !== 'string' && !Array.isArray(element)) {
      throw new Error('arr的元素只允许是object array string 类型的')
    }
    let tempObject = {}
    if (Array.isArray(element)) {
      let [code, value] = element
      if (code === undefined) {
        throw new Error('arr的元素若为Array类型,至少需要有一个元素')
      }
      value = value ?? index
      const temp = { code, value }
      tempObject = Object.assign({}, temp)
    } else if (typeof element === 'string') {
      const code = element
      const value = index
      const temp = { code, value }
      tempObject = Object.assign({}, temp)
    } else {
      let { code, value } = element
      if (code === undefined) {
        throw new Error('arr的元素若为Object类型,至少需要有code属性')
      }
      value = value ?? index
      const temp = { code, value }
      tempObject = Object.assign({}, temp)
    }
    // 编码若出现重复,后者覆盖前者
    obj[tempObject.code] = tempObject.value
  })
  return Object.freeze(obj)
}
/**
 * 传入[item0,item1,item2,item3,...],其中item至少有code和value两个属性
 * 返回一个枚举类,提供code到value,value到item的映射,并可以通过迭代器获得
 * [item0,item1,item2,item3,...]
 */
export class EsEnum {
  constructor(arr, startValue = 1) {
    if (!Array.isArray(arr)) {
      throw new Error('arr 不是 Array')
    }
    let nextValue = startValue
    //  建立value与index的映射关系
    this.indexObject = {}
    this.codeObject = {}
    // 建立code到value的映射关系的同时,生成共迭代器访问的Array
    this.data = arr.map((item, index) => {
      const { code, value } = item

      // code 不允许为undefined
      if ([undefined, null, ''].includes(code)) {
        throw new Error('arr的元素的code 不允许为 空或null或undefined')
      }

      const useValue = value ?? nextValue
      nextValue = (value ?? nextValue) + 1

      this[code] = useValue
      this.indexObject[useValue] = index
      this.codeObject[item.code] = index

      // 使用浅拷贝
      return Object.assign({}, item, { value: useValue })
    })
  }

  /**
     * 默认迭代器
     */
  * [Symbol.iterator]() {
    for (const item of this.data) {
      yield item
    }
  }

  /**
     * 返回array
     */
  toArray() {
    return [...this.data]
  }

  /**
   * 使用value查找与value匹配的枚举项配的结果
   * @param {*} value 待匹配的value值
   * @returns 返回item或者undefined
   */
  getItemByValue(value) {
    const index = this.indexObject[value]
    return this.data[index]
  }

  /**
   * 使用code查找与code匹配的枚举项配的结果
   * @param {*} code 待匹配的code值
   * @returns 返回item或者undefined
   */
  getItemByCode(code) {
    const index = this.codeObject[code]
    return this.data[index]
  }
}

/**
 * 该函数处理window.addEventListener事件传递的event,从event中提取按键的字符串(key)和ASC2码(keyCode)
 * @param {*} event addEventListener
 * @returns {key ,keyCode}
 */
export function KeyboardListener(event) {
  const e = event || window.event || arguments.callee.caller.arguments[0]
  if (!e) return
  const { key, keyCode } = e
  // console.log(key, keyCode)
  return { key, keyCode }
}

/**
 * 获取当前系统颜色
 * @param {String} type 类型
 * @returns 颜色代码
 */
export function GetColorByType(type) {
  switch (type) {
    case '':
    case 'primary':
      return '#409EFF'

    case 'success':
      return '#67C23A'

    case 'danger':
      return '#F56C6C'

    case 'warning':
      return '#E6A23C'

    case 'info':
    default:
      return '#909399'
  }
}
下拉框使用
<LogsType v-model="xxx"/> //引用.vue文件。此时会提供一个下拉框(数据展示的是label值),选中数据后xxx获取的是value值,也可以直接用js通过xxx=LogsType.[code]来赋值 
tag使用
<LogsType v-model="xxx"  :allow-select="false" />
直接使用
<LogsType v-model="xxx"  :allow-select="false" :use-tag="false" /> //增加use-tag属性

$t和i18n是多语言处理,可以看前面的博客

相关推荐
m0_748235242 分钟前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240251 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar1 小时前
纯前端实现更新检测
开发语言·前端·javascript
落魄实习生1 小时前
AI应用-本地模型实现AI生成PPT(简易版)
python·ai·vue·ppt
寻找沙漠的人2 小时前
前端知识补充—CSS
前端·css
GISer_Jing2 小时前
2025前端面试热门题目——计算机网络篇
前端·计算机网络·面试
m0_748245522 小时前
吉利前端、AI面试
前端·面试·职场和发展
理想不理想v2 小时前
webpack最基础的配置
前端·webpack·node.js
pubuzhixing2 小时前
开源白板新方案:Plait 同时支持 Angular 和 React 啦!
前端·开源·github
2401_857600952 小时前
SSM 与 Vue 共筑电脑测评系统:精准洞察电脑世界
前端·javascript·vue.js