vue-virtual-scroll-list(可单选、多选、搜索查询、创建条目)

news2024/11/16 6:03:16

element-ui-解决下拉框数据量过多问题(vue-virtual-scroll-list)_element-ui下拉框数据太多如何优化-CSDN博客

的升级版

参考链接:封装el-select,实现虚拟滚动,可单选、多选、搜索查询、创建条目-CSDN博客

1.封装组件

select.vue

<template>
    <div>
      <el-select
        popper-class="virtualselect"
        class="virtual-select-custom-style"
        :popper-append-to-body="false"
        :value="defaultValue"
        filterable
        :filter-method="filterMethod"
        default-first-option
        clearable
        :placeholder="placeholderParams"
        :multiple="isMultiple"
        :allow-create="allowCreate"
        @visible-change="visibleChange"
        v-on="$listeners"
        @clear="clearChange"
      >
        <virtual-list
          ref="virtualList"
          class="virtualselect-list"
          :data-key="value"
          :data-sources="selectArr"
          :data-component="itemComponent"
          :keeps="keepsParams"
          :extra-props="{
            label: label,
            value: value,
            isRight: isRight,
            isConcat: isConcat,
            concatSymbol: concatSymbol
          }"
        ></virtual-list>
      </el-select>
    </div>
  </template>
  <script>
    import {
      validatenull
    } from '@/utils'
    import virtualList from 'vue-virtual-scroll-list'
    import ElOptionNode from './el-option-node'
    export default {
      components: {
        'virtual-list': virtualList
      },
      model: {
        prop: 'bindValue',
        event: 'change'
      },
      props: {
        // // 父组件传的值
        // selectData: {
        //   type: Object,
        //   default() {
        //     return {}
        //   }
        // },
        // 数组
        list: {
          type: Array,
          default() {
            return []
          }
        },
        // 显示名称
        label: {
          type: String,
          default: ''
        },
        // 标识
        value: {
          type: String,
          default: ''
        },
        // 是否拼接label | value
        isConcat: {
          type: Boolean,
          default: false
        },
        // 拼接label、value符号
        concatSymbol: {
          type: String,
          default: ' | '
        },
        // 显示右边
        isRight: {
          type: Boolean,
          default: false
        },
        // 加载条数
        keepsParams: {
          type: Number,
          default: 10
        },
        // 绑定的默认值
        bindValue: {
          type: [String, Array],
          default() {
            if (typeof this.bindValue === 'string') return ''
            return []
          }
        },
        // 是否多选
        isMultiple: {
          type: Boolean,
          default: false
        },
        placeholderParams: {
          type: String,
          default: '请选择'
        },
        // 是否允许创建条目
        allowCreate: {
          type: Boolean,
          default: false
        }
      },
      data() {
        return {
          itemComponent: ElOptionNode,
          selectArr: [],
          defaultValue: null // 绑定的默认值
        }
      },
      watch: {
        'list'() {
          this.init()
        },
        bindValue: {
          handler(val, oldVal) {
            this.defaultValue = this.bindValue
            if (validatenull(val)) this.clearChange()
            this.init()
          },
          immediate: false,
          deep: true
        }
      },
      mounted() {
        this.defaultValue = this.bindValue
        this.init()
      },
      methods: {
        init() {
          if (!this.defaultValue || this.defaultValue?.length === 0) {
            this.selectArr = this.list
          } else {
            // 回显问题
            // 由于只渲染固定keepsParams(10)条数据,当默认数据处于10条之外,在回显的时候会显示异常
            // 解决方法:遍历所有数据,将对应回显的那一条数据放在第一条即可
            this.selectArr = JSON.parse(JSON.stringify(this.list))
            let obj = {}
            if (typeof this.defaultValue === 'string' && !this.isMultiple) {
              if (this.allowCreate) {
                const arr = this.selectArr.filter(val => {
                  return val[this.value] === this.defaultValue
                })
                if (arr.length === 0) {
                  const item = {}
                  // item[this.value] = `Create-${this.defaultValue}`
                  item[this.value] = this.defaultValue
                  item[this.label] = this.defaultValue
                  item.allowCreate = true
                  this.selectArr.push(item)
                  this.$emit('selChange', item)
                } else {
                  this.$emit('selChange', arr[0])
                }
              }
              // 单选
              for (let i = 0; i < this.selectArr.length; i++) {
                const element = this.selectArr[i]
                if (element[this.value]?.toLowerCase() === this.defaultValue?.toLowerCase()) {
                  obj = element
                  this.selectArr?.splice(i, 1)
                  break
                }
              }
              this.selectArr?.unshift(obj)
            } else if (this.isMultiple) {
              if (this.allowCreate) {
                this.defaultValue.map(v => {
                  const arr = this.selectArr.filter(val => {
                    return val[this.value] === v
                  })
                  if (arr?.length === 0) {
                    const item = {}
                    // item[this.value] = `Create-${v}`
                    item[this.value] = v
                    item[this.label] = v
                    item.allowCreate = true
                    this.selectArr.push(item)
                    this.$emit('selChange', item)
                  } else {
                    this.$emit('selChange', arr[0])
                  }
                })
              }
              // 多选
              for (let i = 0; i < this.selectArr.length; i++) {
                const element = this.selectArr[i]
                this.defaultValue?.map(val => {
                  if (element[this.value]?.toLowerCase() === val?.toLowerCase()) {
                    obj = element
                    this.selectArr?.splice(i, 1)
                    this.selectArr?.unshift(obj)
                  }
                })
              }
            }
          }
        },
        // 搜索
        filterMethod(query) {
          if (!validatenull(query?.trim())) {
            this.$refs.virtualList.scrollToIndex(0) // 滚动到顶部
            setTimeout(() => {
              this.selectArr = this.list.filter(item => {
                return this.isRight || this.isConcat
                  ? (item[this.label].trim()?.toLowerCase()?.indexOf(query?.trim()?.toLowerCase()) > -1 || item[this.value]?.toLowerCase()?.indexOf(query?.trim()?.toLowerCase()) > -1)
                  : item[this.label]?.toLowerCase()?.indexOf(query?.trim()?.toLowerCase()) > -1
              })
            }, 100)
          } else {
            setTimeout(() => {
              this.init()
            }, 100)
          }
        },
        visibleChange(bool) {
          if (!bool) {
            this.$refs.virtualList.reset()
            this.init()
          }
        },
        clearChange() {
          if (typeof this.defaultValue === 'string') {
            this.defaultValue = ''
          } else if (this.isMultiple) {
            this.defaultValue = []
          }
          this.visibleChange(false)
        }
      }
    }
  </script>
<style lang="scss" scoped>
    .virtualselect {
        // 设置最大高度
        &-list {
            max-height:245px;
            overflow-y:auto;
        }
        .el-scrollbar .el-scrollbar__bar.is-vertical {
            width: 0;
        }
    }
    
</style>

el-option-node.vue

<template>
    <el-option
      :key="label+value"
      :label="concatString(source[label], source[value])"
      :value="source[value]"
      :disabled="source.disabled"
      :title="concatString(source[label], source[value])"
    >
      <span>{{ concatString(source[label], source[value]) }}</span>
      <span
        v-if="isRight"
        style="float:right;color:#939393"
      >{{ source[value] }}</span>
    </el-option>
  </template>
  <script>
    export default {
      name: 'ItemComponent',
      props: {
        // 每一行的索引
        index: {
          type: Number,
          default: 0
        },
        // 每一行的内容
        source: {
          type: Object,
          default() {
            return {}
          }
        },
        // 需要显示的名称
        label: {
          type: String,
          default: ''
        },
        // 绑定的值
        value: {
          type: String,
          default: ''
        },
        // 是否拼接label | value
        isConcat: {
          type: Boolean,
          default: false
        },
        // 拼接label、value符号
        concatSymbol: {
          type: String,
          default: ' | '
        },
        // 右侧是否显示绑定的值
        isRight: {
          type: Boolean,
          default() {
            return false
          }
        }
      },
      methods: {
        concatString(a, b) {
          a = a || ''
          b = b || ''
          if (this.isConcat) {
            // return a + ((a && b) ? ' | ' : '') + b
            return a + ((a && b) ? this.concatSymbol : '') + b
          }
          return a
        }
      }
    }
  </script>
   

2.使用:

第一层组件:insuplc.vue

<template>
  <cw-select
      v-model="value"
      :list="list"
      label="name"
      value="value"
      :class="classname" 
      :disabled="disabled" 
      :placeholder-params="placeholder"
      :keeps-params="10"
      :is-concat="false"
      :is-multiple="isMultiple"
      :is-right="false"
      :allow-create="false"
      @change="selectChange"
    />
</template>

<script>
  import CwSelect from '@/components/virtualScrollList/select.vue'
  export default {
      name:'insuplc',
      components: {
          CwSelect
      },
      props: {
        isMultiple: {
            type: Boolean,
            default: false
        },
        defaultValue: {
        },
        disabled: {
          type: Boolean
        },
        classname: {
          type: Object
        },
        placeholder: {
          type: String
        },
      },
      computed: {
        insuplcList() {//医保区划
          return this.$store.state.app.ybDictMap.yb_insuplc
        },
      },
      watch: {
        defaultValue:{
          handler(newVal) {
            this.value = newVal
          },
          immediate: true,
          deep: true
        }
      },
      data() {
          return {
            value:this.defaultValue,
            list:[]
          };
      },
      mounted() {
        this.list = JSON.parse(JSON.stringify(this.insuplcList))
      },
      methods: {
          selectChange(val) {
              this.$emit('change', {value:val})
          }
      }
  };
</script>

第二层:

        <insuplc :isMultiple="true" style="display:inline-block;width: 100%;" placeholder='请选择' :defaultValue="form.insuplc" @change="(val) => changeInsuplc(val)" />

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1377839.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机组成原理-计算机的发展(计算机系统 硬件发展 软件发展 微处理器和微计算机的发展 摩尔定律 发展趋势)

文章目录 总览什么是计算机系统软件硬件的发展第一代第二代第三代第四代微处理器的发展相关人物摩尔定律 软件的发展目前的发展趋势小结 总览 什么是计算机系统 软件 语言处理程序就是编译程序之类的 调试代码就是服务程序 硬件的发展 第一代 逻辑元件&#xff1a;处理电信…

通达信波动指数指标公式,识别盘整还是趋势

波动指数(Choppiness Index)是由澳大利亚商品交易员E.W. Dreiss开发的技术指标&#xff0c;用来判断市场是盘整还是趋势。该指标属于非方向性指标&#xff0c;不用于判断市场方向&#xff0c;而仅用于识别市场趋势。 指标的取值范围为0到100&#xff0c;数值越高&#xff0c;表…

Linux进程管理、ps命令、kill命令

每一个程序在运行的时候都会被操作系统注册为系统中的一个进程 补充一下操作系统的内容&#xff1a; 进程实体&#xff08;又称进程映像&#xff09;&#xff1a;程序段、相关数据段、PCB三部分构成 进程是进程实体的运行过程&#xff0c;是系统进行资源分配的一个独立单位 …

xtdrone用键盘控制无人机飞行 无法起飞

运行案例 解锁无人机螺旋桨转动但无法起飞 也未报错 解决方法&#xff1a; 在QGC中修改&#xff1a;PX4飞控EKF配置 将PX4使用的EKF配置为融合GPS的水平位置与气压计高度。 如果我们想使用视觉定位&#xff0c;就需要把修改配置文件。 此修改意味着EKF融合来自mavros/vision_…

【QUARTZ】springboot+quartz动态配置定时任务

Quartz 介绍 Quartz 定时任务可分为Trigger&#xff08;触发器&#xff09;、Job&#xff08;任务&#xff09;和Scheduler&#xff08;调度器&#xff09;&#xff0c;定时任务的逻辑大体为&#xff1a;创建触发器和任务&#xff0c;并将其加入到调度器中&#xff0c;如下图所…

【Android+物联网】Android封装MQTT连接阿里云物联网平台

前言&#xff1a; 亲测可行&#xff0c;本文实现Android封装MQTT连接阿里云物联网平台。将MQTT协议和连接阿里云平台的操作通过Android studio写入APP中&#xff0c;并简单设计UI。实现手机APP远程控制单片机LED灯亮灭的功能。 关于《Android软件开发》&#xff0c;见如下专栏…

Unity填坑-灯光烘焙相关

Unity填坑-灯光烘焙相关 文章目录 Unity填坑-灯光烘焙相关前言一、Light的模式二、光的效果分类三、各种Light模式与烘焙的说明1.Realtime,实时光2.baked,烘焙光3.mixed,混合 四、实时全局光五、其他说明1.动态物体的全局光照效果2.手机使用烘焙注意的点3.其他设置 前言 项目组…

gem5学习(12):理解gem5 统计信息和输出——Understanding gem5 statistics and output

目录 一、config.ini 二、config.json 三、stats.txt 官方教程&#xff1a;gem5: Understanding gem5 statistics and output 在运行 gem5 之后&#xff0c;除了仿真脚本打印的仿真信息外&#xff0c;还会在根目录中名为 m5out 的目录中生成三个文件&#xff1a; config.i…

Mr_HJ / form-generator项目学习-增加自定义的超融组件(二)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/n…

【pwn】cmcc_simplerop --rop链的构造

程序保护情况检查 32位程序&#xff0c;堆栈不可执行 主函数&#xff1a; 左边又是一堆函数&#xff0c;file看一下 发现是静态链接&#xff0c;那ret2libc不用考虑了&#xff0c;接着看一下有没有int 80 那可以考虑利用rop链调用execve函数&#xff0c;用系统调用的函数参数是…

Matlab 字符识别OCR实验

Matlab 字符识别实验 图像来源于屏幕截图&#xff0c;要求黑底白字。数据来源是任意二进制文件&#xff0c;内容以16进制打印输出&#xff0c;0-9a-f’字符被16个可打印字符替代&#xff0c;这些替代字符经过挑选&#xff0c;使其相对容易被识别。 第一步进行线分割和字符分割…

【动态规划】dp多状态问题

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;那个传说中的man的主页 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;【LeetCode】winter vacation training 目录 &#x1f449;&#x1f3fb;按摩师&#x1f449;&…

C语言操作符详解与进制

目录 一&#xff1a;操作符的分类 二&#xff1a;二进制和进制转换 2.1 2进制转10进制 2.1.1 10进制转2进制数字 2.2 2进制转8进制和16进制 2.2.1 2进制转8进制 2.2.2 2进制转16进制 三&#xff1a; 原码、反码、补码 四&#xff1a;移位操作符 4.1左移操作符 4.2 右…

Mini Event 抢先看!本周六共聚香港,展望 2024 波卡新机遇

2023 冬季波卡黑客松已经进入最终阶段&#xff0c;火热的开发实战比赛之旅以外&#xff0c;我们还为所有 Web3er 准备了一场精彩纷呈的「年终盛会」。来自区块链各领域的技术大咖、行业领军人、亚马逊云科技专家等一线大咖将共聚香港&#xff0c;参与本届黑客松的 Mini Event 活…

MES系统如何进行产品的质量管理

质量管理重点是对产品的检验&#xff0c;这里面包括&#xff1a;采购来料检验、工序检验、入库前检验等几个检验环节&#xff0c;并根据系统设定的检验标准进行检验&#xff0c;检验不通过的不能留到下个环节。质量管理也是万界星空科技云MES中的一个重要组成部分&#xff0c;旨…

认识kafka

认识KafKa 1.什么是KafKa&#xff1a; kafka是一种高吞吐量的分布式发布订阅消息消息队列&#xff0c;有如下特性&#xff1a; 可扩展性&#xff1a;Kafka可以处理大规模的数据流&#xff0c;并支持高并发的生产和消费操作。它可以水平扩展以适应负载的增长。 持久性&#x…

从无到有制作docker镜像、容器详细步骤

1、编写一个Dockerfile文件&#xff0c;内容如下 # 基础镜像jdk,jdk里包含里操作系统 FROM openjdk:8u282-jdk# 工作目录&#xff0c;也就是容器里目录 WORKDIR /home/prq/# 添加ppp目录下的文件到容器/home/prq/里 ADD ./ppp /home/prq/# 暴露端口8080 EXPOSE 8080# 启动脚本…

AdaM: An Adaptive Fine-Grained Scheme for Distributed Metadata Management——泛读论文

ICPP 2019 Paper 分布式元数据论文汇总 问题 为了同时解决元数据局部性和元数据服务器的负载均衡。 现有方法缺陷 基于哈希的方法&#xff1a;zFS [16]&#xff0c;CalvinFS [21]&#xff0c;DROP [24]&#xff0c;AngleCut [8] 静态子树划分&#xff1a;HDFS [6], NFS [14…

【Golang】IEEE754标准二进制字符串转为浮点类型

IEEE754介绍 IEEE 754是一种标准&#xff0c;用于表示和执行浮点数运算的方法。在这个标准中&#xff0c;单精度浮点数使用32位二进制表示&#xff0c;分为三个部分&#xff1a;符号位、指数位和尾数位。 符号位(s)用一个位来表示数的正负&#xff0c;0表示正数&#xff0c;1表…

LInux初学之路linux的磁盘分区/远程控制/以及关闭图形界面/查看个人身份

虚拟机磁盘分配 hostname -I 查看ip地址 ssh root虚拟就ip 远程连接 win10之后才有 远程控制重新启动 reboot xshell 使用&#xff08;个人和家庭版 免费去官方下载&#xff09; init 3 关闭界面 减小内存使用空间 init 5 回复图形界面 runlevel显示的是状态 此时和上…