当前位置: 首页 > 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.dtcms.com/a/287810.html

相关文章:

  • MYSQL 第一次作业
  • 《命令行参数与环境变量:从使用到原理的全方位解析》
  • Flink实时流量统计:基于窗口函数与Redis Sink的每小时PV监控系统(学习记录)
  • UniApp 自定义导航栏:解决安全区域适配问题的完整实践
  • C++基于muduo库从零实现Rpc框架
  • Ubuntu18.04环境下,vscode使用clangd、bear实时准确跳转过程中遇到的compile_commands.json无法解析问题
  • windows wsl ubuntu 如何安装 maven
  • 程序混淆的可行性?
  • PyCharm 入门指南:起步学习、开发环境一体
  • java: DDD using sql server 2019 or Oracle21c
  • WLAN Autoconfig 自启动失效/WIFI功能消失问题解决方案
  • Gradle安装教程
  • 深入理解设计模式之模板模式:优雅地定义算法骨架
  • 在RK3588开发板快速搭建ros环境以及运行ros程序(以usb_cam为例)
  • 云服务器搭建自己的FRP服务。为什么客户端的项目需要用Docker启动,服务端才能够访问到?
  • 详细解读Go中的 fmt包
  • 2025年医疗人工智能发展现状
  • JMeter 元件使用详解
  • 初学者STM32—DMA数据转运
  • [DBC教程 一] DBC文件概述及搭建编辑环境CANdb++ Admin
  • [LGR-233-Div.4]洛谷入门赛#37——8道题题解
  • CF 训练 2 D - E参考代码
  • 面试高频题 力扣 130. 被围绕的区域 洪水灌溉(FloodFill) 深度优先遍历(dfs) 暴力搜索 C++解题思路 每日一题
  • Maven 依赖管理
  • 5.组合模式
  • lowbit小解
  • C#操作WPS表格
  • LVS工作模式和算法的总结
  • 【RK3576】【Android14】摄像头MIPI开发调试
  • 基于单片机智能插座设计/智能开关