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

virtualList 封装使用 虚拟列表 列表优化

虚拟列表 列表优化

  • virtualList 组件封装

virtualList 组件封装

本虚拟列表 要求一次性加载完所有数据 不适合分页
新建一个select.vue 组件页面

<template><div>	<el-select transfer="true"   :popper-append-to-body="true"popper-class="virtualselect"class="virtual-select-custom-style":value="defaultValue"filterable:filter-method="filterMethod"default-first-optionclearable:placeholder="placeholderParams":multiple="isMultiple":allow-create="allowCreate"@visible-change="visibleChange"v-on="$listeners"@clear="clearChange"><virtual-listref="virtualList"class="virtualselect-list":data-key="value":data-sources="selectArr":data-component="itemComponent":keeps="keepsParams":extra-props="{label: label,value: value,labelTwo:labelTwo,isRight: isRight,isConcat: isConcat,isConcatShowText:isConcatShowText,concatSymbol: concatSymbol}"></virtual-list></el-select></div>
</template>
<script>import {validatenull} from '@/utils/validate.js'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: {// 数组list: {type: Array,default() {return []}},// 显示名称1label: {type: String,default: ''},// 显示名称2 labelTwo: {type: String,default: ''},// 标识value: {type: String,default: ''},// 是否拼接label | valueisConcat: {type: Boolean,default: false},isConcatShowText:{type: Boolean,default: false},// 拼接label、value符号concatSymbol: {type: String,default: ' | '},// 显示右边isRight: {type: Boolean,default: false},// 加载条数keepsParams: {type: Number,default: 10},// 绑定的默认值bindValue: {type: [String, Array,Number],default() {if (typeof this.bindValue === 'string') return ''return []}},// 是否多选isMultiple: {type: Boolean,default: false},placeholderParams: {type: String,default: '请选择'},// 是否允许创建条目allowCreate: {type: Boolean,default: true}},data() {return {itemComponent: ElOptionNode,selectArr: [],defaultValue: null // 绑定的默认值}},watch: {'list'() {this.init()},bindValue: {handler(val, oldVal) {this.defaultValue = this.bindValueif (validatenull(val)) this.clearChange()this.init()},immediate: false,deep: true}},mounted() {this.defaultValue = this.bindValuethis.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))if (typeof this.defaultValue === 'string' && !this.isMultiple) {let obj = {}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.defaultValueitem[this.label] = this.defaultValueitem.allowCreate = truethis.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()) {if (element[this.value] === this.defaultValue) {obj = elementthis.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] = vitem[this.label] = vitem.allowCreate = truethis.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()) {if (element[this.value]=== val) {obj = elementthis.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.labelTwo]+'')?.toLowerCase()?.indexOf(query?.trim()?.toLowerCase()) > -1): item[this.label]?.toLowerCase()?.indexOf(query?.trim()?.toLowerCase()) > -1// return this.isRight || this.isConcat? (item[this.label].trim().indexOf(query.trim()) > -1 || (item[this.value]+'').trim().indexOf(query.trim()) > -1)//   : item[this.label].indexOf(query.trim()) > -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>.virtual-select-custom-style{width:100% !important;}
.virtual-select-custom-style ::v-deep .el-select-dropdown__item {// 设置最大宽度,超出省略号,鼠标悬浮显示// options 需写 :title="source[label]"min-width: 300px;max-width: 480px;display: inline-block;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;
}
.virtualselect {// 设置最大高度&-list {max-height:245px;overflow-y:auto;}
}
::-webkit-scrollbar {width: 6px;height: 6px;background-color: transparent;cursor: pointer;margin-right: 5px;
}
::-webkit-scrollbar-thumb {background-color: rgba(144,147,153,.3) !important;border-radius: 3px !important;
}
::-webkit-scrollbar-thumb:hover{background-color: rgba(144,147,153,.5) !important;
}
::-webkit-scrollbar-track {background-color: transparent !important;border-radius: 3px !important;-webkit-box-shadow: none !important;
}
::v-deep  .el-select__tags {flex-wrap: unset;overflow: auto;
}
</style>

新建一个组件 el-option-node.vue

<template><el-option:key="label+value":label="concatString2(source[label], source[labelTwo])":value="source[value]":disabled="source.disabled":title="concatString2(source[label], source[labelTwo])"><span >{{ concatString(source[label], source[labelTwo]) }}</span><spanv-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: ''},// 需要显示的名称labelTwo: {type: String,default: ''},// 绑定的值value: {type: String,default: ''},// 是否拼接label | valueisConcat: {type: Boolean,default: false},isConcatShowText:{type: Boolean,default: false},// 拼接label、value符号concatSymbol: {type: String,default: ' | '},// 右侧是否显示绑定的值isRight: {type: Boolean,default() {return false}}},methods: {//选择后 只显示label//张三concatString(a, b) {a = a || ''b = b || ''if (this.isConcat) {// return a + ((a && b) ? ' | ' : '') + breturn a + ((a && b) ? this.concatSymbol : '') + b}return a},//选择下拉展示时 可以展示label和labelTwo//123||张三concatString2(a, b) {a = a || ''b = b || ''if (this.isConcat) {// return a + ((a && b) ? ' | ' : '') + bif(this.isConcatShowText==true){return a + ((a && b) ? this.concatSymbol : '') + b}else{return a}}return a}}}
</script>

组件建议完成后 在页面使用:

list:数据 [{name:‘张三’,code:‘098’},{}] label:要显示的字段1 labelTwo:要显示的字段2
concat-symbol:拼接符号 is-concat是否拼接 is-multiple:是否多选 allowCreate是否可以创建目录 @change 事件 keeps-params数据多少条

<template><div><virtual-select v-model="item.contractGodsId":list="goodsList" label="name" labelTwo="code" value="id" :placeholder-params="'请选择产品'":keeps-params="10" :is-concat="true" :isConcatShowText="false":concat-symbol="' || '" :is-multiple="false" :allowCreate="false"@change="goodsChange($event,$index)" /></div>
</template>引入组件import VirtualSelect from '@/views/components/virtualList/select'export default {components: {VirtualSelect},}

如果label和labelTwo都填写了,显示效果如下

请添加图片描述

本虚拟列表 要求一次性加载完所有数据 不适合分页

相关文章:

virtualList 封装使用 虚拟列表 列表优化

虚拟列表 列表优化 virtualList 组件封装 virtualList 组件封装 本虚拟列表 要求一次性加载完所有数据 不适合分页 新建一个select.vue 组件页面 <template><div> <el-select transfer"true" :popper-append-to-body"true"popper-class…...

HCIP-九、路由控制

九、路由控制 实验拓扑实验需求及解法1.企业生产网运行 OSPF&#xff0c;完成以下需求&#xff1a;2.数据中心运行 ISIS3.路由引入4.路由策略5.策略路由6.ISP 过滤私网路由 实验拓扑 实验需求及解法 1.企业生产网运行 OSPF&#xff0c;完成以下需求&#xff1a; 1.1 OSPF 进程…...

Vue3水印(Watermark)

APIs 参数说明类型默认值必传width水印的宽度&#xff0c;默认值为 content 自身的宽度numberundefinedfalseheight水印的高度&#xff0c;默认值为 content 自身的高度numberundefinedfalserotate水印绘制时&#xff0c;旋转的角度&#xff0c;单位 number-22falsezIndex追加…...

redis的性能管理、主从复制和哨兵模式

一、redis的性能管理 redis的数据时缓存在内存中的 查看系统内存情况 info memory used_memory:853688 redis中数据占用的内存 used_memory_rss:10522624 redis向操作系统申请的内存 used_memory_peak:853688 redis使用内存的峰值 系统巡检&#xff1a;硬件巡检、数据库 n…...

排序算法:归并排序、快速排序、堆排序

归并排序 要将一个数组排序&#xff0c;可以先将它分成两半分别排序&#xff0c;然后再将结果合并&#xff08;归并&#xff09;起来。这里的分成的两半&#xff0c;每部分可以使用其他排序算法&#xff0c;也可以仍然使用归并排序&#xff08;递归&#xff09;。 我看《算法》…...

Redis 面试题——持久化

目录 1.概述1.1.Redis 的持久化功能是指什么&#xff1f;1.2.Redis 有哪些持久化机制&#xff1f; 2.RDB2.1.什么是 RDB 持久化&#xff1f;2.2.Redis 中使用什么命令来生成 RDB 快照文件&#xff1f;2.3.如何在 Redis 的配置文件中对 RDB 进行配置&#xff1f;2.4.✨RDB 持久化…...

Linux使用固定ip地址

设置静态ip&#xff0c;我们就需要修改 /etc/sysconfig/network-scripts/ifcfg-ens33 配置文件。 vim /etc/sysconfig/network-scripts/ifcfg-ens33 //进入网卡ens33的配置页面 (1) 将 BOOTPROTO dhcp 改成 BOOTPROTO static 也就是将动态ip&#xff0c;改成静态i…...

ESP Multi-Room Music 方案:支持音频实时同步播放 实现音乐互联共享

项目背景 随着无线通信技术的发展&#xff0c;针对不同音频应用领域的无线音频产品正不断涌现。近日&#xff0c;乐鑫科技推出了基于 Wi-Fi 的多扬声器互联共享音乐通信协议——ESP Multi-Room Music 方案。该方案使用乐鑫自研的基于 Wi-Fi 局域网的音频同步播放技术&#xff…...

java分布式锁分布式锁

java分布式&锁&分布式锁 锁 锁的作用&#xff1a;有限资源的情况下&#xff0c;控制同一时间段&#xff0c;只有某些线程&#xff08;用户/服务器&#xff09;能访问到资源。 锁在java中的实现&#xff1a; synchronized关键字并发包的类 缺点&#xff1a;只对单个的…...

2. 流程控制|方法|数组|二维数组|递归

文章目录 流程控制代码块选择结构循环结构跳转控制关键字 方法方法的概述方法的重载Junit单元测试初识全限定类名 Debug 小技巧数组数组的基本概念数组的基本使用数组的声明数组的初始化 JVM内存模型什么是引用数据类型基本数据类型和引用数据类型的区别堆和栈中内容的区别 数组…...

22. 自动装配有哪些限制(需要注意)?

自动装配有哪些限制(需要注意)&#xff1f; 一定要声明set方法覆盖&#xff1a; 你仍可以用 < constructor-arg >和 < property > 配置来定义依赖&#xff0c;这些配置将始终覆盖自动注入。基本数据类型&#xff1a;不能自动装配简单的属性&#xff0c;如基本数据…...

14 网关实战:网关聚合API文档

上节课介绍了网关层的认证鉴权,今天这节介绍一下网关层如何聚合API接口文文档。 为什么需要聚合API接口文档? 大型微服务系统模块众多,木谷博客系统就有9个,如果这些服务的接口地址没有一个统一,那么客户端将要保存每个服务的接口地址,这个肯定是不现实。 先来看一下A…...

css 固定按钮到页面顶部或者底部的实现方式

实现方式 要将按钮固定到顶部或底部&#xff0c;可以使用CSS的定位属性来实现。下面是一种常用的方法&#xff1a; 创建一个包含按钮的HTML元素&#xff0c;例如一个<div>元素。确保给它添加一个唯一的id&#xff0c;以便在CSS中进行定位。 <div id"myButton&qu…...

【Java Spring】SpringBoot常用插件

文章目录 1、Lombok1.1 IDEA社区版安装Lombok1.2 IDEA专业版安装Lombok1.3 Lombok的基本使用 2、EditStarters2.1 IDEA安装EditStarters2.2 EditStarters基本使用方法 1、Lombok 是简化Java开发的一个必要工具&#xff0c;lombok的原理是编译过程中将lombok的注解给去掉并翻译…...

GPT还远远不是真正的智能

GPT是一个基于深度学习的自然语言处理模型&#xff0c;它可以生成逼真的文本。虽然GPT在生成文本方面取得了显著的进展&#xff0c;但它并不具备真正的智能。GPT是通过训练模型来学习语言模式&#xff0c;它不具备理解、推理、判断和主动学习的能力。它只是根据已有的语料库生成…...

计算机网络:网络层

0 本节主要内容 问题描述 解决思路 1 问题描述 两大问题&#xff08;重点&#xff0c;也是难点&#xff09;&#xff1a; 地址管理&#xff1b;路由选择。 1.1 子问题1&#xff1a;地址管理 网络上的这些主机和节点都需要使用一种规则来区分&#xff0c;就相当于是一种身…...

消息队列进阶-1.消息队列的应用场景与选型

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理&#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44…...

浅谈堆和栈内存以及编程语言

浅谈堆和栈内存以及编程语言 栈和堆C 和 C# 的区别&#xff1a;C#总结 编程语言C汇编语言&#xff08;Assembly Language&#xff09;&#xff1a;机器语言&#xff08;Machine Language&#xff09;&#xff1a; 拓展C#依赖注入&#xff08;Dependency Injection&#xff09;模…...

SpringBootWeb案例_01

Web后端开发_04 SpringBootWeb案例_01 原型展示 成品展示 准备工作 需求&环境搭建 需求说明&#xff1a; 完成tlias智能学习辅助系统的部门管理&#xff0c;员工管理 环境搭建 准备数据库表&#xff08;dept、emp&#xff09;创建springboot工程&#xff0c;引入对应…...

C语言数据结构-----栈和队列练习题(分析+代码)

前言 前面的博客写了如何实现栈和队列&#xff0c;下来我们来看一下队列和栈的相关习题。 链接: 栈和队列的实现 文章目录 前言1.用栈实现括号匹配2.用队列实现栈3.用栈实现队列4.设计循环队列 1.用栈实现括号匹配 此题最重要的就是数量匹配和顺序匹配。 用栈可以完美的做到…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?

在工业自动化持续演进的今天&#xff0c;通信网络的角色正变得愈发关键。 2025年6月6日&#xff0c;为期三天的华南国际工业博览会在深圳国际会展中心&#xff08;宝安&#xff09;圆满落幕。作为国内工业通信领域的技术型企业&#xff0c;光路科技&#xff08;Fiberroad&…...