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

实现el-select下拉框,下拉时加载数据

指令

定义指令部分

import { nextTick } from 'vue';
import { debounce } from "lodash-es";export default {mounted(el, binding) {el._binding = binding;// 监听点击事件const handleClick = async () => {await nextTick();const dropdownEl = el.querySelector('.el-select-dropdown__wrap');if (dropdownEl) {// 监听滚动事件setupScrollListener(dropdownEl, binding);}};// 监听 focus 事件(用户可能通过 Tab 键触发下拉菜单)const handleFocus = async () => {await nextTick();const dropdownEl = el.querySelector('.el-select-dropdown__wrap');if (dropdownEl) {// 监听滚动事件setupScrollListener(dropdownEl, binding);}};// 绑定事件el.addEventListener('click', handleClick);el.addEventListener('focus', handleFocus);// 保存事件处理函数,便于后续删除el._handleClick = handleClick;el._handleFocus = handleFocus;},beforeUnmount(el) {// 移除监听事件if (el._handleClick) {el.removeEventListener('click', el._handleClick);delete el._handleClick;}if (el._handleFocus) {el.removeEventListener('focus', el._handleFocus);delete el._handleFocus;}// 移除滚动监听器const dropdownEl = el.querySelector('.el-select-dropdown__wrap');if (dropdownEl && dropdownEl._handleScroll) {dropdownEl.removeEventListener('scroll', dropdownEl._handleScroll);delete dropdownEl._handleScroll;}}
};function setupScrollListener(dropdownEl, binding) {// 清除之前的监听器if (dropdownEl._handleScroll) {dropdownEl.removeEventListener('scroll', dropdownEl._handleScroll);delete dropdownEl._handleScroll;}// 防抖const handleScroll = debounce(async () => {// 判断是否滚动到底部,滚动到底部时调用函数if (dropdownEl.scrollTop + dropdownEl.clientHeight >= dropdownEl.scrollHeight - 50) {if (typeof binding.value === 'function') {await binding.value();}}}, 200);// 保存dropdownEl._handleScroll = handleScroll;// 监听滚动事件dropdownEl.addEventListener('scroll', handleScroll);
}

注册和使用

在main中注册

app.directive('selectScroll', selectScroll)
<el-select  v-selectScroll="handleSelectScroll"><el-option v-for="item in list" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
---------------------------------------------------
const handleSelectScroll = () => {// console.log('触底了')if (list.value.length < total.value) {query.pageNo = query.pageNo + 1getList() }
}

滚动事件例子

滚动事件的参数解析

  • scrollTop: 滚动到顶部的距离
  • clientHeight:可视区域的高度(包括padding,不包括border,margin,滚动条等内容)
  • scrollHeight:元素内容的总高度(包括不可见部分,如被滚动隐藏的内容),常用于判断是否滚动到底部。
  • offsetHeight:元素的总高度(包括 padding、border、margin 和滚动条)
    scrollTop + clientHeight <= scrollHeight
  • 滚动到底部:当 scrollTop + clientHeight >= scrollHeight 时,表示用户已滚动到底部。
  • 滚动到顶部:当 scrollTop === 0 时,表示用户滚动到顶部。

应用例子

实现无限滚动

window.addEventListener("scroll", () => {if (isAtBottom()) {loadMoreData(); // 加载更多数据}
});function isAtBottom() {const scrollTop = window.scrollY || document.documentElement.scrollTop;const clientHeight = window.innerHeight;const scrollHeight = document.documentElement.scrollHeight;return scrollTop + clientHeight >= scrollHeight;
}

平滑滚动到指定位置

window.scrollTo({top: 500, // 滚动到距离顶部500px的位置behavior: "smooth" // 平滑滚动
});

固定导航栏

window.addEventListener("scroll", () => {const nav = document.getElementById("navbar");if (window.scrollY > 100) {nav.classList.add("fixed"); // 滚动超过100px时固定导航栏} else {nav.classList.remove("fixed");}
});

思路

(1) Vue 指令定义
mounted 钩子:

  • 监听 click 和 focus 事件,确保下拉框展开后能够正确绑定滚动事件。

  • 使用 nextTick 确保 DOM 更新完成后再查询下拉框元素。

  • 调用 setupScrollListener 绑定滚动事件。
    beforeUnmount 钩子:

  • 移除所有事件监听器,避免内存泄漏。

  • 清理 click、focus 和 scroll 事件。

(2) 滚动监听逻辑
setupScrollListener 函数:

  • 防抖处理:使用 lodash-es 的 debounce 函数,避免频繁触发回调(设置 200ms 的防抖间隔)。
    滚动到底部判断:
  • 当 scrollTop + clientHeight >= scrollHeight - 50 时,认为滚动到底部(预留 50px 的缓冲区域)。
    回调触发:如果绑定的值是一个函数(binding.value),则调用它。
    (3)为什么监听 click 和 focus 事件
    el-select 下拉框的展开可能通过点击或键盘操作(如 Tab 键)触发。
    通过监听这两种事件,确保无论以何种方式展开下拉框,都能正确绑定滚动事件。

(4) 滚动到底部的条件

  • scrollTop:当前滚动位置。
  • clientHeight:可视区域高度。
  • scrollHeight:内容总高度。
  • 条件:scrollTop + clientHeight >= scrollHeight - 50,表示距离底部还有 50px 时触发回调。
http://www.xdnf.cn/news/15747.html

相关文章:

  • 【RK3576】【Android14】摄像头MIPI开发调试
  • [Python] -实用技巧10- 时间处理:datetime 和 time 模块入门
  • 【数据结构初阶】--双向链表(二)
  • 跨境卖家紧急自查,Endryko Karmadi四季版画版权维权
  • 【嵌入式电机控制#16】电流环(三):过采样提高采集精度看门狗监测总线电压
  • 【Linux系统】进程控制
  • 从0开始学习R语言--Day51--PH检验
  • OpenCV 官翻 1 -介绍、安装、功能概览、核心操作
  • 云计算与 DevOps(开发与运维)
  • sqli-labs靶场通关笔记:第32-33关 宽字节注入
  • Java 中的继承与多态
  • 基于GEE与哨兵2号的土地覆盖分类方法及实现
  • Vue Swiper组件
  • n8n教程分享,从Github读取.md文档内容
  • MySQL(145)如何升级MySQL版本?
  • 【爬虫】04 - 高级数据存储
  • Fortran实战:快速解析气象NC数据
  • OpenCV 官翻8 - 其他算法
  • 牛客-倒置字符串
  • SQL Server和PostgreSQL填充因子
  • debian的pulseaudio删掉也没事
  • SIMATIC WinCC Unified 使用 KPI 优化流程
  • Nacos配置管理
  • 【Unity3D实例-功能-移动】角色移动-通过WSAD(Rigidbody方式)
  • Kafka、RabbitMQ 与 RocketMQ 高可靠消息保障方案对比分析
  • TinyMCE 富文本编辑器在 vue2 中的使用 @tinymce/tinymce-vue
  • MySQL——约束类型
  • Vue 3 中封装并使用 IndexedDB 的完整教程(含泛型、模块化、通用 CRUD)
  • 网络爬虫概念初解
  • 【Unity】YooAsset问题记录