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

实现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.lryc.cn/news/593634.html

相关文章:

  • Docker容器原理和启动策略
  • EP01:【Python 第一弹】基础入门知识
  • aosp15实现SurfaceFlinger的dump输出带上Layer详细信息踩坑笔记
  • 生成式人工智能实战 | 自回归模型详解与实现
  • Linux中添加重定向(Redirection)功能到minishell
  • QGIS和QGC软件的区别
  • LVS部署模式NAT集群案例
  • buildroot运行qemu进行pcie设备模拟,开发驱动的方式
  • 【学习记录】智能客服小桃(进度更新ing)
  • 测试计划(抽奖系统)
  • Redis Sentinel哨兵集群
  • STC增强型单片机寄存器 PWM EEPROM TMOD TCON
  • ElasticSearch:商品SKU+SPU实现join查询,设计及优化
  • JavaScript 中的继承
  • ADC选型设计
  • OpenCV 官翻 4 - 相机标定与三维重建
  • (LeetCode 每日一题) 1233. 删除子文件夹 (排序)
  • 数据集下载网站
  • aosp15上SurfaceFlinger的dump部分新特性-无Layer相关详细信息输出如何解决?
  • 基于Electron打包jar成Windows应用程序
  • 【2025/07/19】GitHub 今日热门项目
  • 【逻辑回归】MAP - Charting Student Math Misunderstandings
  • 2023 年 5 月青少年软编等考 C 语言八级真题解析
  • [故障诊断方向]基于二维时频图像和数据增强技术的轴承故障诊断模型
  • [黑马头条]-基于MinIO存储文章详情
  • 代码随想录算法训练营第二十五天
  • Streamlit 官翻 3 - 开发教程 Develop Tutorials
  • 80、【OS】【Nuttx】【启动】caller-saved 和 callee-saved 示例:栈空间对齐
  • Input输入和Screen相关
  • 轻松学习C++:基本语法解析