vue3 el-select懒加载以及自定义指令方式

 更新时间:2024年04月25日 09:25:50   作者:偷只猫来养  
这篇文章主要介绍了vue3 el-select懒加载以及自定义指令方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

vue3 el-select懒加载以及自定义指令

要求:自定义搜索、自定义指令,滚动懒加载每次展示10条数据

在element-plus中,el-select的选项框是使用popper.js生成的,不在body中,无法直接获取,这时需要巧妙地使用popper-class属性来获取到dom并挂载到el-select进行监听来实现我们的需求。

下面是代码:

<template>
    <el-select 
        v-model="value"
        :loading="loading"
        loading-text="数据加载中..." 
        filterable
        clearable
        popper-class="event-select-poper"
        v-el-select-loadmore="loadmore"
        :placeholder="placeholder"
        style="width: 100%"
        :filter-method="filterOptions"
        @change="handleEventsChange"
        @visible-change="handleVisibleChange">
        <el-option
            v-for="(item, index) in options"
            :key="index"
            :label="item.eventTheme"
            :value="item.logCode">
        </el-option>
    </el-select>
</template>

在vue3的setup语法糖中,以v开头的变量会被识别为指令,一般指令变量命名使用小驼峰语法

<script setup>
import { ref, reactive, watch, nextTick, onBeforeMount } from 'vue'

const props = defineProps({
    eventId: {
        type: [String, Number],
        default: ''
    },
    placeholder: {
        type: String,
        default: ''
    }
})

const emits = defineEmits(['change'])

let options = reactive([])
let loading = ref(false)
let value = ref('')
let allEvents = reactive([
    { eventTheme: '1', logCode: 1 },
    { eventTheme: '2', logCode: 2 },
    { eventTheme: '3', logCode: 3 },
    { eventTheme: '4', logCode: 4 },
    { eventTheme: '5', logCode: 5 },
    { eventTheme: '6', logCode: 6 },
    { eventTheme: '7', logCode: 7 },
    { eventTheme: '8', logCode: 8 },
    { eventTheme: '9', logCode: 9 },
    { eventTheme: '10', logCode: 10 },
    { eventTheme: '11', logCode: 11 },
    { eventTheme: '12', logCode: 12 },
    { eventTheme: '13', logCode: 13 },
    { eventTheme: '14', logCode: 14 },
    { eventTheme: '15', logCode: 15 },
    { eventTheme: '16', logCode: 16 },
])
let allFilterEvents = reactive([
{ eventTheme: '1', logCode: 1 },
    { eventTheme: '2', logCode: 2 },
    { eventTheme: '3', logCode: 3 },
    { eventTheme: '4', logCode: 4 },
    { eventTheme: '5', logCode: 5 },
    { eventTheme: '6', logCode: 6 },
    { eventTheme: '7', logCode: 7 },
    { eventTheme: '8', logCode: 8 },
    { eventTheme: '9', logCode: 9 },
    { eventTheme: '10', logCode: 10 },
    { eventTheme: '11', logCode: 11 },
    { eventTheme: '12', logCode: 12 },
    { eventTheme: '13', logCode: 13 },
    { eventTheme: '14', logCode: 14 },
    { eventTheme: '15', logCode: 15 },
    { eventTheme: '16', logCode: 16 },
])
let pageNum = ref(1)
let pageSize = ref(10)

// 自定义v-el-select-loadmore指令
const vElSelectLoadmore = {
    beforeMount(el, binding) {
        /** 
         * vue2时:
         * el.querySelector('.el-select-dropdown .el-select-dropdown__wrap');
         * vue3时:
         * 在el-select给一个参数popper-class="event-select-poper"           
         * element-plus中el-select的选项是使用的popper.js生成的,无法直接获取
        */
		const selectDom = document.querySelector('.event-select-poper .el-select-dropdown__wrap')
		let loadMores = function() {
            /**
            * scrollHeight 获取元素内容高度(只读)
            * scrollTop 获取或者设置元素的偏移值,常用于, 计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.
            * clientHeight 读取元素的可见高度(只读)
            * 如果元素滚动到底, 下面等式返回true, 没有则返回false:
            * ele.scrollHeight - ele.scrollTop === ele.clientHeight;
            */
            // 判断是否到底
			const isBase = this.scrollHeight - this.scrollTop <= this.clientHeight + 20
			if (isBase) {
                // 增加防抖
				binding.value && binding.value()
			}
		}
        // 将获取到的dom和函数挂载到el-select上,实例销毁时好处理
		el.selectDomInfo = selectDom
		el.selectLoadMore = loadMores
        // 监听滚动事件
		selectDom?.addEventListener('scroll', loadMores.bind(selectDom))
	},
    // 实例销毁
	beforeUnmount(el) {
		if (el.selectLoadMore) {
			el.selectDomInfo.removeEventListener('scroll', el.selectLoadMore)
			delete el.selectDomInfo
			delete el.selectLoadMore
		}
	}
}

watch(() => allFilterEvents, () => {
    let startIndex = pageNum.value * pageSize.value - pageSize.value
    let endIndex = pageNum.value * pageSize.value
    options = allFilterEvents.slice(startIndex, endIndex)
}, {
    immediate: true,
    deep: true
})

onBeforeMount(() => {
    loadEvents()
})

// 模拟懒加载
const loadmore = () => {
    // 数据加载完成之后,不需要再执行懒加载
    if (allEvents.length <= options.length) { return }
    pageNum.value++
    nextTick(() => {
        loading.value = true
        let startIndex = pageNum.value * pageSize.value - pageSize.value
        let endIndex = pageNum.value * pageSize.value
        options = [
            ...options,
            ...allFilterEvents.slice(startIndex, endIndex)
        ]
        loading.value = false
    })
}

// 自定义过滤函数
const filterOptions = (query = '') => {
    pageNum.value = 1
    nextTick(() => {
        if(query === ''){
            // 搜索词为空时,显示全部
            allFilterEvents = JSON.parse(JSON.stringify(allEvents))
        }else{
            // 搜索词不为空时,从所有关键字列表中筛选匹配项
            let arr = allEvents.filter((item) => {
                return item.includes(query)
            })
            $set(this, 'allFilterEvents', arr)
        }
    })
}

// 下拉框隐藏时,重置分页已经过滤得到的列表
const handleVisibleChange = (visible) => {
    if(!visible){
        pageNum.value = 1
        nextTick(() => {
            allFilterEvents = JSON.parse(JSON.stringify(allEvents))
        })
    }
}

// 获取事件列表
const loadEvents = () => {
    loading.value = true
    allFilterEvents = allEvents
    // 调用接口
    loading.value = false
}

const handleEventsChange = (val) => {
    emits('change', val)
}
</script>

el-select懒加载(自定义指令selectLazyload)实现大数据量展示和搜索

需求:在一个el-form里使用el-select提供选择用户的下拉框,但是每次打开弹框的时候由于数据量过大都需要加载很久才能将数据渲染出来,并且页面异常卡顿

封装懒加载指令

在指令文件夹下新建文件 selectLazyload.js

export default {
    bind (el, binding) {
        // 获取选择器下的滚动框DOM
        const SELECTWRAP_DOM = el.querySelector(
            `.el-select-dropdown__wrap`
        ); 
        // 如果找到了滚动框DOM,则添加滚动事件监听器
        if (SELECTWRAP_DOM) {
            SELECTWRAP_DOM.addEventListener("scroll", function () {
                // 如果滚动到底部,则调用传入的回调函数
                const condition = SELECTWRAP_DOM.scrollHeight - SELECTWRAP_DOM.scrollTop <= SELECTWRAP_DOM.clientHeight;
                if (condition) {
                    binding.value();
                }
            });
        }
    },
};

在main.js或directive/index.js中注册这个自定义指令

import selectLazyLoad from './module/selectLazyLoad'
Vue.directive('selectLazyLoad', selectLazyLoad)

html结构:在el-select上添加 

v-selectLazyLoad="loadMore":filter-method="userFilterMethod"

<el-select v-model="transferTesterNo" filterable placeholder="请选择测试人" style="width:100%" v-selectLazyLoad="loadMore" :filter-method="userFilterMethod">
	<UOptins :isMobile="isMobile" v-for="{nickName, userName, organName, roleName} of options" :key="userName" :label="nickName" :organName="organName" :value="userName" :roleName="roleName" />
</el-select>

js结构

// 加载更多
loadMore(){
	// 如果截取的长度==获取到的所有option长度将不再截取
	if (this.options.length == this.userOptions?.length) return;
	this.userPageNum++;
	this.getScrollUser();
},
 
// 截取页面显示的实际option
getScrollUser(){
	// 过滤出前5条用户信息  实际展示的数据 options  全部数据 userOptions
	this.options = this.userOptions.slice(0, this.userPageNum * 5);
},
// 搜索功能
userFilterMethod(value){
	// 手动触发下拉框回滚至顶部,避免触发v-selectLazyLoad指令
	document.querySelector(`.el-select-dropdown__wrap`).scrollTop = 0;
	if (!value?.length) return this.getScrollUser();
	this.options = this.userOptions.filter((item) => item.nickName?.includes(value)) || [];
},

首次加载需要在 获取数据的接口内写上

this.userOptions = rows
this.getScrollUser()

// 在data 中定义变量 
userOptions: [],
options: [],
userPageNum: 1,

这样即可实现 在滚动到底部时动态加载后面的数据,且可以搜索

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • vue实现滚动加载的表格

    vue实现滚动加载的表格

    在系统开发中遇到了这么一个问题:后端一次性返回上百条的数据,我需要把返回的数据全部显示在表格里,而且甲方爸爸明确指定了表格是不允许使用分页的。可是当使用a-table装载上百条数据时,页面出现了明显的卡顿现象。只能使用滚动加载的方案来代替了。
    2021-06-06
  • vue中为什么在组件内部data是一个函数而不是一个对象

    vue中为什么在组件内部data是一个函数而不是一个对象

    这篇文章主要介绍了vue中为什么在组件内部data是一个函数而不是一个对象,本文通过示例代码给大家讲解的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • vue2.0基于vue-cli+element-ui制作树形treeTable

    vue2.0基于vue-cli+element-ui制作树形treeTable

    这篇文章主要介绍了vue2.0基于vue-cli+element-ui制作树形treeTable,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • vue阻止事件冒泡和捕获方式

    vue阻止事件冒泡和捕获方式

    这篇文章主要介绍了vue阻止事件冒泡和捕获方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-06-06
  • 详解vue中使用express+fetch获取本地json文件

    详解vue中使用express+fetch获取本地json文件

    本篇文章主要介绍了详解vue中使用express+fetch获取本地json文件,非常具有实用价值,需要的朋友可以参考下
    2017-10-10
  • Vue3封装全局自定义指令实现按钮权限控制功能实例

    Vue3封装全局自定义指令实现按钮权限控制功能实例

    在Vue应用中自定义指令是一种强大的功能,可以用于封装DOM操作逻辑,这篇文章主要介绍了Vue3封装全局自定义指令实现按钮权限控制功能的相关资料,需要的朋友可以参考下
    2025-07-07
  • vue弹窗消息组件的使用方法

    vue弹窗消息组件的使用方法

    这篇文章主要为大家详细介绍了vue弹窗消息组件的使用方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-04-04
  • Vue使用正则校验文本框为正整数

    Vue使用正则校验文本框为正整数

    这篇文章主要介绍了Vue使用正则校验文本框为正整数问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • vue进入页面时滚动条始终在底部代码实例

    vue进入页面时滚动条始终在底部代码实例

    这篇文章主要介绍了vue进入页面时滚动条始终在底部,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • 前端VUE3项目部署到linux服务器(CentOS 7)完整步骤

    前端VUE3项目部署到linux服务器(CentOS 7)完整步骤

    这篇文章主要介绍了前端VUE3项目部署到linux服务器(CentOS 7)的相关资料,包括项目打包、连接服务器、安装和配置Nginx、上传文件以及配置Nginx,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2026-01-01

最新评论