发布时间:2026/8/23 20:31:55
Vue3 + ElementPlus 2.4.x 自定义指令:解决el-select滚动加载3大坑点 Vue3 ElementPlus 2.4.x 自定义指令解决el-select滚动加载3大坑点在Vue3项目中ElementPlus的el-select组件因其丰富的功能和良好的兼容性成为开发者处理下拉选择需求的首选。然而当面对大数据量场景时直接一次性渲染所有选项会导致严重的性能问题。滚动加载Infinite Scroll是解决这一问题的有效方案但在实际开发中我们往往会遇到几个棘手的坑点。1. Teleport机制带来的DOM结构变化ElementPlus 2.4.x版本中el-select的下拉菜单默认通过Teleport挂载到body元素下。这一变化导致传统的DOM查询方式失效我们需要调整自定义指令的实现逻辑。export default { beforeMount(el, binding) { // 使用popper-class作为查询选择器 const selectWrap document.querySelector( .${binding.arg} .el-select-dropdown__wrap ) const scrollHandler function() { const isBottom this.scrollHeight - this.scrollTop this.clientHeight 5 if (isBottom) { binding.value() } } selectWrap?.addEventListener(scroll, scrollHandler) el._scrollHandler scrollHandler el._selectWrap selectWrap }, beforeUnmount(el) { el._selectWrap?.removeEventListener(scroll, el._scrollHandler) } }关键调整点不再直接查询.el-select-dropdown__wrap而是通过传入的popper-class定位添加5px的容差阈值避免精确匹配导致的触发不灵敏将DOM引用和事件处理器挂载到el上便于卸载时清理提示建议为每个el-select设置唯一的popper-class避免多个下拉框互相干扰。2. 事件监听与内存泄漏防范滚动加载的核心是监听滚动事件但如果处理不当很容易造成内存泄漏。以下是常见的三种问题场景及解决方案2.1 事件未正确移除// 错误示例直接添加匿名函数无法移除 selectWrap.addEventListener(scroll, function() { // ... }) // 正确做法使用具名函数引用 const handler function() { /*...*/ } selectWrap.addEventListener(scroll, handler) // 卸载时 selectWrap.removeEventListener(scroll, handler)2.2 组件卸载时未清理{ beforeUnmount(el) { // 必须检查元素是否存在 if (el._selectWrap el._scrollHandler) { el._selectWrap.removeEventListener(scroll, el._scrollHandler) } // 清除引用 delete el._selectWrap delete el._scrollHandler } }2.3 动态popper-class处理当popper-class是动态生成时需要特殊处理template el-select :popper-classselect-${uniqueId} v-select-loadmore:[select-${uniqueId}]loadMore !-- options -- /el-select /template script setup import { nanoid } from nanoid const uniqueId nanoid() /script3. 性能优化与用户体验提升单纯的滚动加载实现可能还不够我们需要考虑以下优化点3.1 防抖处理import { debounce } from lodash-es const scrollHandler debounce(function() { const isBottom this.scrollHeight - this.scrollTop this.clientHeight 5 if (isBottom !loading.value) { binding.value() } }, 200, { leading: true, trailing: true })参数说明参数类型默认值说明leadingbooleanfalse是否在延迟开始前调用trailingbooleantrue是否在延迟结束后调用maxWaitnumber-最大等待时间3.2 加载状态反馈template el-select v-select-loadmoreloadMore el-option v-foritem in options :valueitem.value :labelitem.label / template #footer div v-ifloading classloading-more el-icon classis-loadingLoading //el-icon 加载中... /div div v-else-ifnoMore classno-more没有更多了/div /template /el-select /template style .loading-more, .no-more { padding: 8px 0; text-align: center; color: var(--el-text-color-secondary); font-size: 12px; } /style3.3 数据分页策略推荐的后端接口参数设计const loadMore async () { if (loading.value || noMore.value) return loading.value true try { const res await api.getList({ page: page.value 1, pageSize: 20, keyword: searchKeyword.value }) if (res.data.length) { options.value.push(...res.data) page.value } else { noMore.value true } } finally { loading.value false } }分页参数对比分页方式优点缺点适用场景页码分页实现简单数据新增时可能重复数据变动不频繁游标分页避免重复实现复杂实时数据流时间分页自然排序依赖时间字段时间序列数据4. 完整实现与最佳实践下面是一个生产环境可用的完整实现方案4.1 自定义指令封装// directives/selectLoadmore.js import { debounce } from lodash-es export default { beforeMount(el, binding) { const { arg: popperClass, value: callback } binding if (typeof callback ! function) { console.warn([v-select-loadmore] 必须传入函数) return } const selectWrap document.querySelector( .${popperClass} .el-select-dropdown__wrap ) if (!selectWrap) { console.warn([v-select-loadmore] 未找到下拉框容器请检查popper-class: ${popperClass}) return } const checkBottom function() { const { scrollHeight, scrollTop, clientHeight } this return scrollHeight - scrollTop clientHeight 5 } const scrollHandler debounce(function() { if (checkBottom.call(this)) { callback() } }, 200) selectWrap.addEventListener(scroll, scrollHandler) // 存储引用以便清理 el._selectLoadmore { selectWrap, scrollHandler } }, beforeUnmount(el) { const { selectWrap, scrollHandler } el._selectLoadmore || {} if (selectWrap scrollHandler) { selectWrap.removeEventListener(scroll, scrollHandler) } delete el._selectLoadmore } }4.2 全局注册// main.js import { createApp } from vue import App from ./App.vue import selectLoadmore from ./directives/selectLoadmore const app createApp(App) app.directive(select-loadmore, selectLoadmore) app.mount(#app)4.3 组件使用示例template el-select v-modelselectedValue filterable remote :remote-methodhandleSearch :popper-classselectPopperClass v-select-loadmore:[selectPopperClass]loadMore visible-changehandleVisibleChange el-option v-foritem in options :keyitem.value :labelitem.label :valueitem.value / template #footer div v-ifloading classselect-footer el-icon classis-loadingLoading //el-icon span加载中.../span /div div v-else-ifisEnd classselect-footer没有更多数据了/div /template /el-select /template script setup import { ref, onMounted } from vue import { nanoid } from nanoid const selectPopperClass select-${nanoid()} const selectedValue ref() const options ref([]) const loading ref(false) const isEnd ref(false) const pageInfo ref({ page: 1, pageSize: 20, keyword: }) const fetchData async (reset false) { if (loading.value) return loading.value true try { const res await api.getData({ ...pageInfo.value, page: reset ? 1 : pageInfo.value.page }) if (reset) { options.value res.data isEnd.value false } else { options.value.push(...res.data) } if (res.data.length pageInfo.value.pageSize) { isEnd.value true } else if (!reset) { pageInfo.value.page } } finally { loading.value false } } const loadMore () { if (!isEnd.value !loading.value) { fetchData() } } const handleSearch (keyword) { pageInfo.value.keyword keyword fetchData(true) } const handleVisibleChange (visible) { if (!visible) { // 重置状态 pageInfo.value.page 1 isEnd.value false } } onMounted(() { fetchData(true) }) /script style .select-footer { padding: 8px 16px; text-align: center; color: var(--el-text-color-secondary); font-size: 12px; display: flex; align-items: center; justify-content: center; gap: 6px; } /style在实际项目中我们还需要考虑以下细节网络错误时的重试机制空数据状态展示移动端触摸事件优化多选模式下的特殊处理

相关新闻

2026/8/24 9:43:09

STM32与LV3296高精度数据采集系统设计与优化

1. 项目背景与核心组件选型在工业自动化和精密测量领域,数据采集系统的性能直接影响整个系统的可靠性和精度。LV3296作为一款16位分辨率、500ksps采样率的高性能ADC芯片,与STM32F407VGT6这款168MHz主频的Cortex-M4微控制器的组合,为需要高精度…

2026/8/24 12:16:09

向量化分析引擎与 AI 辅助存储排障:版本更新后先测什么

向量化分析引擎与 AI 辅助存储排障:版本更新后先测什么 向量化引擎升级后,不能只在一类 CPU 上看吞吐。不同代际的处理器对 AVX 指令、频率和内存带宽的反应不同;同一版 AI 排障 Agent 也可能因为指标字段变化而误判。因此需要把硬件兼容、算…

2026/8/24 12:16:09

物理AI与世界模型实战:从零构建物理仿真环境与智能体规划

最近在跟进AI领域的前沿动态时,发现一个非常有意思的趋势:无论是顶尖的学术机构还是头部科技公司,都在将目光投向一个名为“物理AI”的交叉领域,并将其与“世界模型”这一宏大愿景紧密结合。这不再是实验室里的概念探讨&#xff0…

2026/8/24 12:16:09

如何用scrcpy把安卓手机投屏到电脑:5分钟上手的完整教程

如何用scrcpy把安卓手机投屏到电脑:5分钟上手的完整教程 【免费下载链接】scrcpy Display and control your Android device 项目地址: https://gitcode.com/GitHub_Trending/sc/scrcpy scrcpy 是一款免费的开源 Android 投屏工具:它通过 USB 或 …

2026/8/24 12:16:09

Not your weights,not your brain

对于X-plore仓库: 技术含量不是最高的,商业模式是没有的,代码是AI写的。用持续性和学习能力证明:在信息爆炸的时代,帮别人省时间,本身就是巨大的价值

2026/8/24 12:16:08

AI Agent在商超场景的工程化落地:从需求拆解到生产部署

1. 这篇文章真正要解决的问题如果你正在负责一个线下零售门店的数字化升级项目,或者你是一名对AI落地实体商业感兴趣的技术人,那么最近你一定被各种“AI Agent”刷屏了。从写代码的Devin到能规划行程的GPTs,AI似乎无所不能。但当你真的想把一…

2026/8/24 12:11:08

基于LangGraph与Ollama构建自我改进型AI智能体:从原理到实战

你好,我是专注于AI与软件开发实战的技术博主。最近,斯坦福大学的CS329A课程《自我改进型AI智能体》引起了广泛关注,它系统性地揭示了AI智能体如何通过自我迭代变得越来越“聪明”。这不仅是前沿学术课题,更是当下企业招聘&#xf…

2026/8/24 0:07:22

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/24 1:12:32

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/24 8:17:29

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/24 1:09:25

3条命令跑通LocalAI:无GPU本地AI引擎部署

3条命令跑通LocalAI:无GPU本地AI引擎部署 【免费下载链接】LocalAI LocalAI is the open-source AI engine. Run any model - LLMs, vision, voice, image, video - on any hardware. No GPU required. 项目地址: https://gitcode.com/GitHub_Trending/lo/LocalAI…

2026/8/24 1:09:25

AI推理性能测试怎么做:MLPerf Inference完整上手指南

AI推理性能测试怎么做:MLPerf Inference完整上手指南 【免费下载链接】inference Reference implementations of MLPerf inference benchmarks 项目地址: https://gitcode.com/gh_mirrors/inf/inference 同一个模型换一张卡,速度快多少你知道吗&a…

2026/8/23 13:29:45

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/23 6:14:43

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/23 4:22:01

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…