当前位置: 首页 > article >正文

Element UI-Select选择器结合树形控件终极版

Element UI Select选择器控件结合树形控件实现单选和多选,并且通过v-model的方式实现节点的双向绑定,封装成vue组件,文件名为electricity-meter-tree.vue,其代码如下:

<template>
  <div>
    <el-select
        :value="selectedId"
        :multiple="multiple"
        placeholder="请选择"
        ref="selectTree"
        clearable
        @change="handleChange"
        @clear="handleClear">
      <el-option v-for="form in hiddenForm" :key="form.id" :value="form.id" :label="form.label" hidden/>
      <div style="padding: 10px 14px">
        <el-input placeholder="输入关键字进行过滤" v-model="filterText" clearable>
          <template #suffix>
            <el-button type="text" icon="el-icon-search" style="max-width: 22px">
              <i class="el-icon-search" style="display: none;"></i>
            </el-button>
          </template>
        </el-input>
        <el-tree
            v-loading="loading"
            :data="treeData"
            ref="tree"
            :props="defaultProps"
            node-key="id"
            accordion
            default-expand-all
            :filter-node-method="filterNode"
            :show-checkbox="multiple"
            :check-strictly="checkStrictly"
            :highlight-current="highLightCurrent"
            @check-change="handleCheckChange"
            @node-click="handleNodeClick">
            <!-- 来源于省的电表以蓝色底标识。-->
             <template v-slot="{ node, data }">
               <span v-if="data.sources === 'province'" style="background: #1890ff;color: #FFFFFF;padding: 2px;">
                 {{ node.label}}
               </span>
               <span v-else>{{ node.label}}</span>
            </template>
        </el-tree>
      </div>
    </el-select>
  </div>
</template>

<script>

export default {
  model: {
    prop: 'value',
    event: 'change'
  },
  props: {
    value: {
      type: [Object, Array], // 根据实际情况选择类型
      default: () => {} // 格式:{id: 'xx', label: 'xx'}或者[{id: 'xx', label: 'xx'}]
    },
    multiple: { // 是否多选
      type: Boolean,
      default: false
    },
    checkStrictly: { // 父子是否不互相关联
      type: Boolean,
      default: false
    },
  },
  watch: {
    value: {
      handler (val) {
        if (this.multiple) {
          if (val && val.length > 0) {
            this.hiddenForm = val;
            this.selected = val;
          }else {
            this.hiddenForm = [{id: '', label: ''}];
            this.selected = [];
          }
        } else {
          if (val) {
            this.selected = val;
            this.hiddenForm = [val];
          }else {
            this.hiddenForm = [{id: '', label: ''}];
            this.selected = null;
          }
        }
      },
      immediate: true,
      deep: true
    },
    filterText(val) {
      this.$refs.tree.filter(val);
    }
  },
  computed: {
    selectedId () {
      if (this.multiple) {
        return this.selected && this.selected.length > 0 ? this.selected.map(item => item.id) : [];
      }
      return this.selected? this.selected.id : '';
    },
  },
  data () {
    return {
      filterText: '',
      treeData: [],
      defaultProps: {
        children: 'children',
        label: 'label',
        id: 'id',
        disabled: 'disabled'
      },
      selected: [],// 格式:{} 或者 []
      hiddenForm: [
        {
          id: '',
          label: ''
        },
      ],
      highLightCurrent: true,
      loading: false,
    }
  },
  methods: {
    filterNode(value, data) {
      if (!value) return true;
      return data.label.indexOf(value) !== -1;
    },
    handleCheckChange (data, checked) {
      if (this.multiple) { // 多选
        const nodes = this.$refs.tree.getCheckedNodes();
        this.hiddenForm = nodes.length > 0 ? nodes : [{id: '', label: ''}];
        // 保证重现加载数据时,已选中的数据不被清除
        if (checked) {
          if (!this.selected || this.selected.length === 0) {
            this.selected = nodes;
          }else {
            // 定义一个函数来去重
            function removeDuplicates(array, uniqueKey) {
              let seen = new Map(); // 使用 Map 来存储已见过的 id 和对应对象
              // 遍历数组中的每个对象
              for (let obj of array) {
                // 如果 Map 中还没有这个 id,就添加进去
                if (!seen.has(obj[uniqueKey])) {
                  seen.set(obj[uniqueKey], obj); // 使用 id 作为 key,对象作为 value
                }
              }
              // 从 Map 中提取所有对象组成新的数组返回
              return Array.from(seen.values());
            }
            this.selected = removeDuplicates([...this.selected, ...nodes], 'id');
          }
        }else {
          this.selected = this.selected?.filter(item => item.id !== data.id);
        }
        this.$emit('change', this.selected);
      } else {}
    },
    handleNodeClick (data, node) {
      if (data.disabled) return;
      if (this.multiple) {} else { // 单选
        this.hiddenForm = [
          {
            id: data.id,
            label: data.label
          }
        ]
        this.selected = data;
        this.$emit('change', data);
        // 使 input 失去焦点,并隐藏下拉框
        // node.isLeaf && this.$refs.selectTree.blur();
      }
    },
    handleChange (value) {
      if (!value) return;
      this.selected = this.selected?.filter(item => value.includes(item.id));
      this.$emit('change', this.selected);
      this.multiple && this.$refs.tree.setCheckedKeys(this.selectedId);
    },
    handleClear () {
      this.selected = [];
      this.multiple && this.$refs.tree.setCheckedKeys([]);
      this.hiddenForm = [
        {
          id: '',
          label: ''
        }
      ];
      this.highLightCurrent = false;
      this.$emit('change', this.multiple ? [] : null);
    },
    getTreeDataAsync() {
      // 这里模拟调用后端接口返回的数据
      this.treeData = [
        {
          id: '1',
          label: 'XX市智能电表',
          children: [
            {
              id: '1-1',
              label: '通用智能电表A',
              children: [
                {
                  id: '1-1-1',
                  label: '通用智能电表B',
                  sources: 'province',
                },
                {
                  id: '1-1-2',
                  label: '通用智能电表C',
                },
              ]
            },
            {
              id: '1-2',
              label: '智能电表01',
              children: [
                {
                  id: '1-2-1',
                  label: '智能电表02',
                  sources: 'province',
                }
              ]
            },
          ]
        }
      ];
    }
  },
  created() {
    this.getTreeDataAsync();
  },
}
</script>

<style scoped>
</style>

该组件的用法如下:

 <electricity-meter-tree v-model="electricityMeter" multiple checkStrictly @change="electricityMeterChange"/>
  1. 引入组件:electricity-meter-tree
  2. 如果multiple为true多选时,那么electricityMeter的结构为[{id: ‘xx’, label: ‘xx’}],如果 mutilple为false单选时,那么electricityMeter的结构为{id: ‘xx’, label: ‘xx’}
  3. checkStrictly是否父子不互相关联,前提是multiple为true
  4. change事件也可以获取选中的节点

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


http://www.kler.cn/a/572766.html

相关文章:

  • Ruby爬虫如何控制并发数量:爬取京东电子产品
  • 如何在matlab中创建自己的库
  • CSS【实战】模拟 html 的 title 属性(鼠标悬浮显示提示文字)
  • OBOO鸥柏丨LCD液晶室外AI触控屏广告一体机,服务区交互新趋势
  • python:pymunk + pygame 模拟六边形中小球弹跳运动
  • 文件上传漏洞:upload-labs靶场11-20
  • RISCV下Dovetail移植(2)——原子操作
  • TikTok矩阵系统介绍
  • 特辣的海藻!8
  • @PostConstruct注解的作用
  • 【前端学习笔记】Git 原理及面试题
  • 用本地浏览器打开服务器上使用的Tensorboard
  • 自学微信小程序的第十三天
  • 【Spring Boot 应用开发】-04-02 自动配置-数据源-手撸一个最简持久层工具类
  • 驱动开发系列43 - Linux 显卡KMD驱动代码分析(四)- DRM设备操作
  • Golang的数据库分库分表
  • 【网络安全】API安全防护完整指南
  • 【计算机网络入门】TCP拥塞控制
  • OpenGL ES -> GLSurfaceView纹理贴图
  • 词向量(Word Embedding)