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

elementplus 二次封装 select 自定义指令上拉加载更多 完美解决 多次接口调用 重新加载数据多次调用数据!!!

效果:(名字都是测试数据 随便乱写的 若有冒犯 请联系)

select 二次封装

网上的这种自定义指令上拉加载更多的实例有很多,但是基本都是有缺陷和问题的。为了记录这个问题 我研究了一天,在今天终于搞定了 呜呜呜。

网上遇到的问题:

1、封装的自定义指令没法用(后续会讲解原理)

2、封装完 select 之后 如果一个页面有多个封装的 select 会导致多次触发加载更多。比如一个页面有3个 select 其中一个触发了加载更多 则其他两个也会同时触发(如果是调接口则会触发三次)(后续会讲解原理)

3、当上拉触底多次(比如调用接口可能是 pageindex:1, pageindex:2, pageindex:3 获取三次的数据),这个时候点击其他区域 将 option 隐藏起来 这时候重新点击 select 会重新触发三次的接口请求。(后续会讲解原理)

开始二次封装 selec 组件(只写重点代码其他自己参考)

"element-plus": "^2.8.0",
"vue": "^3.2.47",

1、子组件

1、components/el-load-search-select/index.vue

<template><!-- :popper-class-name 和 :popper-class 和 v-loadmore 为这里的重点!!!!--><el-select:popper-class-name="popperClassName"v-model="selectedValue"v-loadmore="handleLoadMore"placeholder="请选择":popper-class="popperClassName":multiple="!isOnlySingle"collapse-tagsreserve-keywordv-bind="$attrs":teleported="true"filterableremote:remote-method="handleRemoteMethod"@visible-change="handleVisibleChange"@change="onSelectChange"><el-option v-if="isShowAll" label="全部" value=""></el-option><!-- :label="item.Name" --><el-optionv-for="item in baseSelectUserList":key="item.Id":label="item.Name":value="item[keyName]"><span style="float: left">{{ item.Name }}</span><span style="float: right; color: #8492a6; font-size: 13px">{{onShowLabel(item)}}</span></el-option></el-select>
</template>
<script setup lang="ts">const props = defineProps({/** 双向绑定 */modelValue: {type: [String, Array as () => Array<string>],default: null,},/** 机构参数 */orgIds: {type: [String, Array as () => Array<string>],default: "",},/** 科室参数 */deptIds: {type: [String, Array as () => Array<string>],default: "",},/** 角色 */roleTypes: {type: [String, Array as () => Array<string>],default: "",},/** 是否获取权限内的数据 */scopeable: {type: Boolean,default: false,},/** 是否是通过redash */isRedash: {type: Boolean,default: false,},/** 选择的是否是单选 */isOnlySingle: {type: Boolean,default: true,},/** 双向绑定的值是哪个字段 */keyName: {type: String,default: "Id",},/** 关键字搜索默认数据 */remoteName: {type: String,default: "",},/** dtoType */dtoTypeName: {type: String,default: "QueryUserOutputDto3",},/** 下拉列表显示什么数据 */selectShowLabel: {type: String,default: "",},/** 是否显示全部选择 */isShowAll: {type: Boolean,default: true,},/** 是否显示默认列表数据(主要是做回显操作) */isUseDefaultList: {type: Boolean,default: false,},/** 一个页面多次使用 select popperClassName不能重复 切记!!!!!!  */popperClassName: {require: true,type: String,},
});
</script>

2、父组件

<el-load-search-selectv-model="transferAssistant.oldPhone"placeholder="请选择医助":role-types="['doctor']":scopeable="false":is-redash="false":is-only-single="true"key-name="PhoneNumber"popper-class-name="oldAssistant" // 这里是重点style="width: 140px;"/>

3、自定义指令

src/directive/elSelectLoadMore.ts

import { debounce, DebouncedFunc } from "lodash";
export default {mounted(el: any, binding: { value: () => void; },vnode:any) {console.log('el', el)// 这里的popper-class-name就是使用 select 时候传递的 popper-class-name="oldAssistant" !!!!!const popperClassName = el.getAttribute('popper-class-name')console.log('popperClassName', popperClassName);let scrollWrap = document.querySelector(`.${popperClassName} .el-select-dropdown__wrap`)!// let scrollWrap = document.querySelector('.selectPopperClass .el-select-dropdown__wrap')!// 把监听的方法防抖一下const handle = debounce((e) => {console.log('scrollWrap.scrollTop', scrollWrap.scrollTop);console.log('scrollWrap.scrollHeight', scrollWrap.scrollHeight);console.log('scrollWrap.clientHeight', scrollWrap.clientHeight);let scrollDistance = scrollWrap.scrollHeight - scrollWrap.scrollTop// 比如此处预留10个像素的位置用于触底if (scrollWrap.clientHeight + 10 > scrollDistance) {binding.value() // 触底通知一下,外界}}, 170)// 绑定监听滚动事件scrollWrap?.addEventListener('scroll', handle)// 方法挂载到元素身上便于解绑时使用el._hanlde = handle},unmounted(el: { _hanlde: EventListenerOrEventListenerObject | null; }, binding: any) {let scrollWrap: any = document.querySelector('.el-scrollbar__wrap')console.log('scrollWrap', scrollWrap)scrollWrap?.removeEventListener('scroll', el._hanlde)el._hanlde = null}
}

src/directive/index.ts

import loadmore from "./elSelectLoadMore";
// 自定义指令对象,用于遍历注册
const directives = {loadmore,
} as any;
// 批量注册指令并暴露到main.js中去便于注册
export default {install(app: { directive: (arg0: string, arg1: any) => void }) {Object.keys(directives).forEach((key) => {app.directive(key, directives[key]);});},
};

src/mian.ts

import directive from './directive';
app.use(directive);

上面是所有的代码,接下来讲解上面的三个问题

三个问题的讲解

1、 封装的自定义指令没法用

原因出在let scrollWrap = document.querySelector()! 时候里面写的 class 实际在 dom 中不存在

在 elementplus 时候 select 进行了重构 element 的封装不适合了

2、封装完 select 之后 如果一个页面有多个封装的 select 会导致多次触发加载更多

这里的 select 是在 body 上面的 里面的 class 名称都是一样的 如果你  let scrollWrap = document.querySelector()!里面写的 class 名称是一样的话 就是导致这个问题

因为你每一个都是相同的 class 都回触发自定义指令

而我这边是自己传入了一个自定义属性(上面框起来 有 oldAssistant 和 newAssistant) 通过querySelector(自定义属性)! 那就每一个select不一样了

所以为什么我很强调popper-class-name="" 使用组件的这个属性为什么一定要不一样

3、点击其他区域 将 option 隐藏起来 这时候重新点击 select 会重新触发多次请求

在之前可能你请求了三次 数据可能有100条  假设每一条高度是20px 这时候你的整体高度就是2000px  这个时候你重新点击 select  又去加载数据(远程搜索 空字符串)可能只有30条 这个时候高度就是600px 那么之前的滚动条是在最底部的 elementplus 记录了你上一次的位置 这次你的高度只有600px 完全没有到达之前的高度 就会导致一直触发上拉触底 一直等到你的高度>=2000px的时候才会停止(以上只是推理 没有验证)

完美收官!! 若有问题 下方评论哦 对你有用是我最大的荣幸

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • LeetCode-字母异位词分组
  • 用R语言进行数据类型的检查和基础转换
  • 如果将一个对象赋值给 ref,那么这个对象将通过 reactive() 转为具有深层次响应式的对象。这也意味着如果对象中包含了嵌套的 ref,它们将被深层地解
  • rk3568-linux sdk编译update.img时以当前时间进行命名
  • 前端开发有什么专业术语吗?
  • Golang | Leetcode Golang题解之第335题路径交叉
  • Android 12系统源码_多屏幕(二)模拟辅助设备功能开关实现原理
  • SecureCRT for Mac/Win:安全高效的专业终端SSH工具软件
  • 重修设计模式-创建型-原型模式
  • 超详细!!!electron-vite-vue开发桌面应用之配置路由router(五)
  • CopyOnWriteArrayList技术探究
  • C:每日一题:二分查找
  • DevExpress开发WPF应用实现对话框总结:编织界面的艺术之旅
  • 搭建jenkins+k8s过程中遇到的问题
  • HarmonyOS应用开发学习-ArkTs声明式UI描述
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • 【mysql】环境安装、服务启动、密码设置
  • angular学习第一篇-----环境搭建
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • CentOS7 安装JDK
  • co.js - 让异步代码同步化
  • Flannel解读
  • Javascript设计模式学习之Observer(观察者)模式
  • JS笔记四:作用域、变量(函数)提升
  • JS实现简单的MVC模式开发小游戏
  • python学习笔记 - ThreadLocal
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • Zepto.js源码学习之二
  • 第2章 网络文档
  • 技术胖1-4季视频复习— (看视频笔记)
  • 蓝海存储开关机注意事项总结
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 前端代码风格自动化系列(二)之Commitlint
  • 探索 JS 中的模块化
  • 突破自己的技术思维
  • 微信如何实现自动跳转到用其他浏览器打开指定页面下载APP
  • 用element的upload组件实现多图片上传和压缩
  • ​十个常见的 Python 脚本 (详细介绍 + 代码举例)
  • ​学习笔记——动态路由——IS-IS中间系统到中间系统(报文/TLV)​
  • "无招胜有招"nbsp;史上最全的互…
  • # 数论-逆元
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • $ git push -u origin master 推送到远程库出错
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (机器学习-深度学习快速入门)第一章第一节:Python环境和数据分析
  • (免费领源码)Java#Springboot#mysql农产品销售管理系统47627-计算机毕业设计项目选题推荐
  • (七)理解angular中的module和injector,即依赖注入
  • (生成器)yield与(迭代器)generator
  • (十)【Jmeter】线程(Threads(Users))之jp@gc - Stepping Thread Group (deprecated)
  • (四)JPA - JQPL 实现增删改查
  • (五)activiti-modeler 编辑器初步优化
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • (转)nsfocus-绿盟科技笔试题目