自定义Select下拉框内容的增、删、改

716 阅读1分钟

背景

 在公司遇到一个奇怪的需求,用户可以自定义下拉框的内容,也就是说用户看到下拉框里面没有自己喜欢的选项,他可以对已有的选项进行修改,或者直接自己新增;当时感觉还很奇葩,后来想想,也许是为了给用户更高的选择自由度吧,没有你喜欢的选项,你可以自己新建一个😁😁😄。

实现原理

这里是vue2 + element-ui为基础

实现方式主要是通过自定义option的方式实现,代码主要分为三块:编辑区、选择区、添加自定义模板区

代码: 目前不支持搜索功能

<template>
  <div class="">
    <el-select
      v-model="value"
      placeholder="请选择"
      style="width: 50%; position: relative;"
      @visible-change="visibleChange($event)"
      @change="selectOption"
      :loading="selLoadingBool"
      loading-text="数据更新中...">
      <el-option
        v-for="item in materialTitleListData"
        :key="item.id"
        :label="item.content"
        :value="item.content"
        :disabled="disableBool"
        :style="{ height: item.id === -99 ? '0px' : '', marginBottom: item.id === materialTitleListData[materialTitleListData.length - 1].id ? '40px' : '' }">
        <!-- 编辑区 -->
        <div v-if="item.id === itemId">
          <el-input
            v-model="inputValue"
            @keyup.enter.native="updateTemplete(inputValue, item.id, '')"
            :maxlength="maxlength"
            show-word-limit
            :placeholder="placeholder" 
            style="width:300px; margin:0"/>
          <div style="float: right;">
            <el-button 
              @click.stop="updateTemplete(inputValue, item.id, '')" 
              icon="el-icon-check" type="text"
              style="fontSize: 15px;padding: 0;"/>
            <el-button 
              @click.stop="updateTemplete(inputValue, item.id, 'cancle')" 
              icon="el-icon-close" 
              type="text"
              style="color:red;fontSize: 15px;padding: 0;"/>
          </div>
        </div>
        <!-- 选择区 -->
        <div v-else>
          <span style="float: left">{{ item.content }}</span>
          <div style="float: right; fontSize: 13px;">
            <el-button 
              :disabled="disableBool" 
              @click.stop="getMaterialInfo(item)" 
              icon="el-icon-edit" 
              type="text"
              style="fontSize: 15px;"/>
            <el-button 
              :disabled="disableBool" 
              @click.stop="deleteItemTitle(item)" 
              icon="el-icon-delete" 
              type="text"
              :style="{ fontSize: '15px', color: disableBool ? '#C0C4CC' : 'red' }"/>
          </div>
        </div>
      </el-option>
      <!-- 添加自定义模板区 -->
      <div style="position: absolute; bottom:0px;width: 100%;height: 45px;background-color: #fff;z-index: 999;">
        <div v-if="addCustomTempleteBool">
          <el-input 
            v-model="addCustomValue" 
            @input="getCustomValue" 
            @keyup.enter.native="saveTemplate"
            style="margin:6px 0 0 20px;width:300px;" 
            :maxlength="maxlength"
            show-word-limit
            :placeholder="placeholder" />
          <div style="float: right; margin: 10px 20px 0 0;">
            <el-button 
              @click.stop="saveTemplate" 
              icon="el-icon-check" type="text"
              style="fontSize: 15px;padding: 0;"/>
            <el-button 
              @click.stop="addCustomTempleteBool = false, disableBool = false, addCustomValue = ''"
              icon="el-icon-close" 
              type="text" 
              style="color:red;fontSize: 15px;padding: 0;"/>
          </div>
        </div>
        <el-button v-else 
          :disabled="disableBool" 
          type="text" 
          @click="addCustomTempleteBool = true, disableBool = true"
          class="addCustom">
          {{ bottomName }}
        </el-button>
      </div>
    </el-select>
  </div>
</template>

<script>
/**
 * 接收的参数
 * @prop materialTitleList:array   select数据源
 * @prop bottomName:string  自定义标题模板名称
 * @prop selLoadingBool:boolean 下拉框的加载状态
 * @prop maxlength:number  文字最大长度
 * 抛出的事件
 * @prop selectOption  选中的option
 * @prop updateTemplete  更新当前修改的模板
 * @prop deleteItemTitle 删除当前option
 * @prop saveTemplate 保存添加的模板
 */
export default {
  name: 'customizeSelect',
  props: {
    materialTitleList: {
      type: Array,
      default: () => ([])
    },
    bottomName: {
      type: String,
      default: ' + 添加自定义标题模板'
    },
    selLoadingBool: {
      type: Boolean,
      default: false
    },
    maxlength: {
      type: Number,
      default: 35
    }
  },
  data() {
    return {
      placeholder: '点击“√”或回车保留模板',
      value: '',
      disableBool: false,
      itemId: -1,
      inputValue: '',
      addCustomTempleteBool: false,
      addCustomValue: '',
      materialTitleListData: []
    };
  },
  watch: {
    materialTitleList: {
      handler(val) {
        if (val.length === 0) {
          // 当没有数据传来时,需要一条 假数据 进行占位
          this.materialTitleListData = [{id: -99, content: '--'}];
        } else {
          this.materialTitleListData = val;
        }
      },
      immediate: true,
      deep: true
    }
  },
  methods: {
    // 下拉/收起事件
    visibleChange(bool) {
      if (!bool) {
        this.initModify();
      }
    },
    // 选中的option
    selectOption(e) {
      this.$emit('selectOption', e);
    },
    // 取消/更新option的修改
    updateTemplete(val, id, type) {
      if (type !== 'cancle') {
        this.$emit('updateTemplete', val, id);
      }
      this.initModify();
    },
    // 获取每条数据信息
    getMaterialInfo(item) {
      this.disableBool = true;
      this.itemId = item.id;
      this.inputValue = item.content;
    },
    // 删除当前项
    deleteItemTitle(item) {
      this.$emit('deleteItemTitle', item);
    },

    // 自定义模板模块
    // 获取自定义模板的值
    getCustomValue(e) {
      this.addCustomValue = e;
    },
    // 点击“√”或回车保留模板
    saveTemplate() {
      this.$emit('saveTemplate', this.addCustomValue);
      this.initModify();
    },
    // 下拉框初始化
    initModify() {
      this.itemId = -1;
      this.addCustomTempleteBool = false;
      this.disableBool = false;
      this.addCustomValue = '';
    }
  },
};
</script>
<style lang="scss" scoped>
.addCustom {
  width: 100%;
  height: 100%;
  line-height: 100%;
}
</style>