使用VUE自定义组件封装数据字典实战

背景

照惯例,先交待下背景,从真实需求出发,讲述设计思路和实现方式。
软件系统中,会有一些成组的常量值,来描述业务实体的属性,如性别、证件类型、审批状态等。我们通常称之为数据字典,作为系统后台管理的一个独立功能,来维护字典类型以及对应的字典值。后端功能和实现都比较简单,没什么好说的,今天重点要说的是前端的封装。

设计与实现

对于数据字典,前端展现往往有三种常用的形式,下拉列表、单选按钮组和复选框组,其中,最常用是下拉列表,这里就以下拉列表的实现为例来说明,其他两种类似,不重复描述。

技术栈采用的还是vue2.0,UI组件库使用element ui。element ui提供了Select 选择器(传送门:https://element.eleme.cn/#/zh-CN/component/select),实现效果如下:
在这里插入图片描述

官方示例代码如下:

<template>
  <el-select v-model="value" placeholder="请选择">
    <el-option
      v-for="item in options"
      :key="item.value"
      :label="item.label"
      :value="item.value">
    </el-option>
  </el-select>
</template>

<script>
  export default {
    data() {
      return {
        options: [{
          value: '选项1',
          label: '黄金糕'
        }, {
          value: '选项2',
          label: '双皮奶'
        }, {
          value: '选项3',
          label: '蚵仔煎'
        }, {
          value: '选项4',
          label: '龙须面'
        }, {
          value: '选项5',
          label: '北京烤鸭'
        }],
        value: ''
      }
    }
  }
</script>

这是从纯前端角度来展示如何使用,在软件系统中,数据是来自于后端的,也就是前端需要调用后端的api,拿到数据来填充列表。

直接使用select组件,是不是可以呢?答案是可以用,但用起来比较繁琐,需要在页面加载的时候,调用后端API接口拿数据,在data中定义存放字典数据的变量,并且一个实体编辑页面,使用到字典属性往往不止一个,三五个也比较常见,这时候,需要定义多个变量来存放字典项以及加载数据,开发工作量变大且容易出错。
那有没有办法让使用变得更方便呢?答案也简单,就是自定义封装一个组件来实现。我们的目标是传入一个数据字典的类型编码,组件内部调用后端API,完成数据的加载与存储,在选择项变化时,自动更新绑定的对应的业务实体的属性值。同时,在业务实体的编辑页面,也能自动绑定和显示已选择的字典项。

封装是在elment ui的select组件的基础上进行的,先附上完整源码。

<template>
  <el-select
    :value="value"
    :size="size"
    clearable
    :multiple="multiple"
    :disabled="readonly"
    style="width:100%;margin:0px auto;"
    @change="change"
  >
    <el-option
      v-for="item in dictionaryItemList"
      :key="item.code"
      :value="item.code"
      :label="item.label"
    />
  </el-select>
</template>

<script>

export default {
  model: {
    prop: 'value',
    event: 'change'
  },
  props: {
    value: {
      type: [String, Array],
      required: false,
      default: ''
    },
    code: {
      type: String,
      default: ''
    },
    readonly: {
      type: Boolean,
      required: false,
      default: false
    },
    size: {
      type: String,
      default: ''
    },
    multiple: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      dictionaryItemList: []
    }
  },
  watch: {
    code: {
      immediate: true,
      handler: 'loadData'
    }
  },
  methods: {
    change(value) {
      this.$emit('change', value)
    },
    loadData() {
      if (this.code) {
        this.dictionaryItemList = []
        this.$api.system.dictionaryType.getItem(this.code).then(res => {
          this.dictionaryItemList = res.data
        })
      }
    }
  }
}
</script>

下面重点说下封装自定义组件需要注意的点。
1.很重要的一点,是设置model选项。因为默认情况下,model使用名为 value 的 prop 和名为 input 的事件,对于我们要封装的select组件,事件应该使用chang而不是input,所以需要做如下设置:

 model: {
    prop: 'value',
    event: 'change'
  }

2.不仅要考虑单选情况,还需要考虑多选情况,因此value属性,类型是一个数组,可以是String,也可以是Array。

 value: {
      type: [String, Array],
      required: false,
      default: ''
    }

3.为了组件的可配置性,将select组件自身的属性,设置为prop属性,这样在使用的时候,就能通过属性绑定的方式灵活配置了。

  	readonly: {
      type: Boolean,
      required: false,
      default: false
    },
    size: {
      type: String,
      default: ''
    },
    multiple: {
      type: Boolean,
      default: false
    }

4.code是最重要的属性,即我们上面提到的数据字典类型的编码,是后端查找字典项的依据。需要注意的是,这里并未使用mounted事件来加载数据,而是使用了watch来监控该值的变化。这么做是考虑到在某些业务场景下,需要动态刷新下拉列表的数据项,如多个下拉列表联动。

 watch: {
    code: {
      immediate: true,
      handler: 'loadData'
    }
  }
   ……
 loadData() {
  if (this.code) {
    this.dictionaryItemList = []
    this.$api.system.dictionaryType.getItem(this.code).then(res => {
      this.dictionaryItemList = res.data
    })
  }
 }

5.选择项变化时,通过change事件,调用emit,把最新的值传递给使用方,这一步很关键。

 change(value) {
      this.$emit('change', value)
 }

整体而言,封装工作并不复杂,下面看下使用方如何来调用

  <!--表单区域 -->
      <el-form-item label="名称" prop="name">
        <el-input v-model="entityData.name" :readonly="readonly" />
      </el-form-item>
      <el-form-item label="编码" prop="code">
        <el-input v-model="entityData.code" :readonly="readonly" />
      </el-form-item>  
      <el-form-item label="数据类型" prop="dataType">
        <dictionary-select
          v-model="entityData.dataType"
          :code="constant.ENTITY_MODEL_PROPERTY_TYPE"
          :readonly="readonly"
        
        />
      </el-form-item>

      <el-form-item label="控件类型" prop="widgetType">
        <dictionary-select
          v-model="entityData.widgetType"
          :code="widgetType"
          :readonly="readonly"
        />

  

效果图如下:
在这里插入图片描述

通过封装后,整个下拉列表就成为了一个相对独立的组件了。只需要传入一个数据字典类型的编码,就能自动加载数据,更新绑定,对于使用的页面,无需定义额外的字典项存储变量,是不是很简洁方便?

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学海无涯,行者无疆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值