Vue3 + ElementPlus 2.4.x 自定义指令:解决el-select滚动加载3大坑点

发布时间:2026/7/9 15:02:01
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在实际项目中我们还需要考虑以下细节网络错误时的重试机制空数据状态展示移动端触摸事件优化多选模式下的特殊处理

相关新闻

ps网站建设目标怎么定才不跑偏?老站长掏心窝子的3点建议

ps网站建设目标怎么定才不跑偏?老站长掏心窝子的3点建议

你是不是也遇到过这种情况:网站做完了,流量没见涨,反而因为服务器费用心疼不已。或者明明设计图很精美,用户进来转两圈就跑了。别急,这篇文就是来解决这个烂摊子的。咱们先说个大实话。很多老板或者刚入行的运营,一上来就盯着“我要做个像苹果官网那样炫酷的网站”。结果…

发布时间:2026/7/9 15:01:15
2024网站建设行业分析报告:别再被割韭菜了,这才是真相

2024网站建设行业分析报告:别再被割韭菜了,这才是真相

本文关键词:网站建设行业分析报告做网站这事儿,水太深了。你找一家报价3000的,给你套个模板,半年后打不开。你找一家报价3万的,说是定制开发,结果代码乱得像一坨屎,连个移动端都适配不好。最后钱花了,网站没流量,老板还觉得你办事不力。这年头,谁还信“包教包会”、“…

发布时间:2026/7/9 15:01:10
别信那些吹上天的pc端网站建设电话,看完这篇能省三万块

别信那些吹上天的pc端网站建设电话,看完这篇能省三万块

本文关键词:pc端网站建设电话真的受够了。上周三凌晨两点,我还在改代码。不是我的代码,是客户的。那个所谓的“专业团队”,把一套五年前的模板改改颜色就敢收八万。我盯着屏幕,手都在抖。不是因为累,是因为气。气那些拿着模板当定制卖的人,气那些不懂装懂的老板,更气自…

发布时间:2026/7/9 15:01:08
跑断腿也搞不定验收?马鞍山建设工程监督站网站避坑指南,真话都在这

跑断腿也搞不定验收?马鞍山建设工程监督站网站避坑指南,真话都在这

上周去马鞍山市政务服务中心,排队的人比蚂蚁还多。手里攥着一叠厚厚的资料,心里那个慌啊,生怕哪个章盖错了,又要回去重跑。以前总觉得,工程质量监督就是走个过场,直到自己成了甲方代表,才懂其中的水深。那天阳光挺毒的,晒得人眼睛都睁不开。我站在大厅里,看着玻璃门上…

发布时间:2026/7/9 16:01:20
衡阳衡南网站建设避坑指南:别被低价忽悠了,这几点你得知道

衡阳衡南网站建设避坑指南:别被低价忽悠了,这几点你得知道

你是不是也在为搞个网站头疼?我懂。前两天有个衡南的老哥找我,说之前找的那家做网站的公司,把网站做出来一看,丑得没法看。加载速度还慢,手机打开直接卡死。他气得半死,说花了三千块,结果连个像样的页面都没有。这真不是个例。在衡阳衡南这边,很多小老板觉得网站嘛,随…

发布时间:2026/7/9 16:00:48
2026年私有化部署商城系统平台服务商推荐,哪家更专业?

2026年私有化部署商城系统平台服务商推荐,哪家更专业?

当下企业数字化转型加速,线上商城成为营收增长的核心载体。相比于通用SaaS共享商城,私有化部署商城系统具备数据独立、安全性高、可定制性强、适配性广等核心优势。 这也是中大型企业、连锁品牌、批发供应链企业,优先选择私有化部署商城的核心…

发布时间:2026/7/9 16:01:09
四川林峰脉建设工程有限公司网站:揭秘四川工程圈那些不为人知的潜规则与真实报价

四川林峰脉建设工程有限公司网站:揭秘四川工程圈那些不为人知的潜规则与真实报价

四川林峰脉建设工程有限公司网站最近好多朋友私信问我,说在四川做工程太水了,深不见底。我也确实深有体会,毕竟在这个圈子摸爬滚打这么多年,见过太多因为不懂行而踩坑的老板。今天咱们不整那些虚头巴脑的官话,就聊聊真实的行业现状,顺便说说为啥我推荐大家多看看四川林峰…

发布时间:2026/7/9 16:00:21
档案库房温湿度监测设备常见型号适配场景对照表

档案库房温湿度监测设备常见型号适配场景对照表

原标题:档案馆专用温湿度变送器推荐(分两类:盛世宏博档案以太网主力款行业通用备选款)添加图片注释,不超过 140 字(可选)全部适配《DA/T13 档案库房规范》《JGJ25 档案馆建筑设计规范》&#xf…

发布时间:2026/7/9 16:00:42
别再被忽悠了,c 网站建设真的不是套模板那么简单

别再被忽悠了,c 网站建设真的不是套模板那么简单

昨天跟一个做传统制造业的老哥喝茶,他愁眉苦脸地跟我说,花了三万块做个网站,结果连个像样的访客都没有,客服电话都快打爆了,全是问能不能退款的。我听完心里咯噔一下,这哪是网站建设,这简直是“网站销毁”。很多人对 c 网站建设 有个巨大的误解,觉得找个外包公司,给个…

发布时间:2026/7/9 15:58:34
江苏建设个人信息网站 怎么查才不踩坑?

江苏建设个人信息网站 怎么查才不踩坑?

昨晚十一点半,我还在被窝里刷手机。不是看剧,是焦虑。前脚刚收到个骚扰电话,后脚短信就来了。那种感觉,就像有人在你家窗户底下装了窃听器。气不打一处来。我想查查我的信息到底泄露没。这时候脑子里蹦出个念头:江苏建设个人信息网站。别笑,这名字听着挺官方,挺靠谱。我…

发布时间:2026/7/9 0:01:26
珠海住房和建设局网站怎么查备案?老中介的掏心窝子话,别等踩坑才后悔

珠海住房和建设局网站怎么查备案?老中介的掏心窝子话,别等踩坑才后悔

珠海这地方,买房的人是真多,但水也是真深。很多人第一反应是去中介门店看海报,或者刷短视频听主播喊口号。说句不好听的,那些都是包装出来的“美好”。真正能定心丸的,其实就在那个看起来有点丑、操作有点繁琐的官方平台上——珠海住房和建设局网站。我干了五年房产,见过…

发布时间:2026/7/9 0:01:49
别再被忽悠了!揭秘专业网站建设效果的底层逻辑与真实成本

别再被忽悠了!揭秘专业网站建设效果的底层逻辑与真实成本

很多老板找我聊网站,开口就是“给我整一个高大上的”,预算还卡得死死的,三五千块钱想做出几十万的效果。说实话,这种需求我一般直接劝退。为啥?因为专业网站建设效果从来不是靠堆砌特效或者套用模板能搞定的,它是商业逻辑、技术实现和用户心理的精密结合。今天咱不整那些…

发布时间:2026/7/9 0:01:56
做个人信息管理网站建设,这3个坑我踩了七年,你千万别再跳

做个人信息管理网站建设,这3个坑我踩了七年,你千万别再跳

做了七年建站,见过太多老板花大钱买模板,最后发现根本没法用。特别是现在大家都讲究数据隐私,想搞个个人信息管理网站建设,结果越搞越乱。这篇文不整虚的,直接说怎么把这套系统落地,让你自己的数据真正听话。先说个真事儿。去年有个做自由职业的朋友找我,他说想建个网站…

发布时间:2026/7/9 15:43:56
杨凌规划建设局网站怎么查最新规划?老杨说点大实话

杨凌规划建设局网站怎么查最新规划?老杨说点大实话

杨凌规划建设局网站你是不是也遇到过这种情况?想看看自家旁边要修路,还是建公园。翻遍了手机,搜出来的全是几年前的旧闻。或者好不容易找到个入口,页面加载慢得像蜗牛。心里那个急啊,真的,懂的人都懂。我是老杨,在杨凌混了十几年,跟这行打交道不少。今天不跟你扯那些虚…

发布时间:2026/7/9 15:43:42
杭州网站建设 seo 避坑指南:别被那些只会套模板的忽悠了

杭州网站建设 seo 避坑指南:别被那些只会套模板的忽悠了

昨天半夜两点,我还在改一个客户的后台,咖啡都凉透了。这哥们儿是做机械配件的,在余杭那边,找的前一家公司花了八千块做了个站,结果上线一个月,百度连个影子都没有。他急得给我打电话,说是不是被黑了。我让他把链接发过来,打开一看,好家伙,那代码乱得跟刚被猫抓过的毛…

发布时间:2026/7/8 4:42:51
建站7年才悟出的网站建设思路,别再花冤枉钱了

建站7年才悟出的网站建设思路,别再花冤枉钱了

做建站这行整整7年了。 见过太多老板花几万块, 最后做出来的网站像个垃圾场。 今天不整那些虚头巴脑的术语。 就聊聊我踩过的坑, 和真正能落地的网站建设思路。很多老板一上来就问: “多少钱能做个高大上的?” 我通常直接劝退。 因为方向错了, 你给再多钱也是打水漂。 真正…

发布时间:2026/7/9 15:45:02
合肥的网站建设避坑指南:别被低价忽悠,这3个细节决定生死

合肥的网站建设避坑指南:别被低价忽悠,这3个细节决定生死

做企业官网最怕什么?不是技术难,是交钱后没人管,或者上线一个月连个访客都没有。这篇东西不扯虚的,直接告诉你怎么在合肥找个靠谱的团队,或者自己怎么避坑。先说个大实话,我在合肥混这行五年多,见过太多老板因为贪便宜吃大亏。你去百度搜“合肥的网站建设”,出来一堆报…

发布时间:2026/7/9 15:44:20
别被忽悠了!德州网站建设那些坑,我拿真金白银换来的教训

别被忽悠了!德州网站建设那些坑,我拿真金白银换来的教训

做这行久了,心里就憋着一股火。每次看到客户拿着网上抄来的模板,问我能不能做成“苹果官网”那种效果。我就想笑。真的,太想笑了。今天咱不整那些虚头巴脑的专业术语。就聊聊德州网站建设里,那些让人头秃的真实事儿。我有个客户,老张。他是做德州本地建材的,实在人。当初…

发布时间:2026/7/9 15:45:20