vue3 el-select懶加載以及自定義指令方式
vue3 el-select懶加載以及自定義指令
要求:自定義搜索、自定義指令,滾動(dòng)懶加載每次展示10條數(shù)據(jù)
在element-plus中,el-select的選項(xiàng)框是使用popper.js生成的,不在body中,無(wú)法直接獲取,這時(shí)需要巧妙地使用popper-class屬性來(lái)獲取到dom并掛載到el-select進(jìn)行監(jiān)聽(tīng)來(lái)實(shí)現(xiàn)我們的需求。
下面是代碼:
<template> <el-select v-model="value" :loading="loading" loading-text="數(shù)據(jù)加載中..." 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語(yǔ)法糖中,以v開(kāi)頭的變量會(huì)被識(shí)別為指令,一般指令變量命名使用小駝峰語(yǔ)法
<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時(shí): * el.querySelector('.el-select-dropdown .el-select-dropdown__wrap'); * vue3時(shí): * 在el-select給一個(gè)參數(shù)popper-class="event-select-poper" * element-plus中el-select的選項(xiàng)是使用的popper.js生成的,無(wú)法直接獲取 */ const selectDom = document.querySelector('.event-select-poper .el-select-dropdown__wrap') let loadMores = function() { /** * scrollHeight 獲取元素內(nèi)容高度(只讀) * scrollTop 獲取或者設(shè)置元素的偏移值,常用于, 計(jì)算滾動(dòng)條的位置, 當(dāng)一個(gè)元素的容器沒(méi)有產(chǎn)生垂直方向的滾動(dòng)條, 那它的scrollTop的值默認(rèn)為0. * clientHeight 讀取元素的可見(jiàn)高度(只讀) * 如果元素滾動(dòng)到底, 下面等式返回true, 沒(méi)有則返回false: * ele.scrollHeight - ele.scrollTop === ele.clientHeight; */ // 判斷是否到底 const isBase = this.scrollHeight - this.scrollTop <= this.clientHeight + 20 if (isBase) { // 增加防抖 binding.value && binding.value() } } // 將獲取到的dom和函數(shù)掛載到el-select上,實(shí)例銷毀時(shí)好處理 el.selectDomInfo = selectDom el.selectLoadMore = loadMores // 監(jiān)聽(tīng)滾動(dòng)事件 selectDom?.addEventListener('scroll', loadMores.bind(selectDom)) }, // 實(shí)例銷毀 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 = () => { // 數(shù)據(jù)加載完成之后,不需要再執(zhí)行懶加載 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 }) } // 自定義過(guò)濾函數(shù) const filterOptions = (query = '') => { pageNum.value = 1 nextTick(() => { if(query === ''){ // 搜索詞為空時(shí),顯示全部 allFilterEvents = JSON.parse(JSON.stringify(allEvents)) }else{ // 搜索詞不為空時(shí),從所有關(guān)鍵字列表中篩選匹配項(xiàng) let arr = allEvents.filter((item) => { return item.includes(query) }) $set(this, 'allFilterEvents', arr) } }) } // 下拉框隱藏時(shí),重置分頁(yè)已經(jīng)過(guò)濾得到的列表 const handleVisibleChange = (visible) => { if(!visible){ pageNum.value = 1 nextTick(() => { allFilterEvents = JSON.parse(JSON.stringify(allEvents)) }) } } // 獲取事件列表 const loadEvents = () => { loading.value = true allFilterEvents = allEvents // 調(diào)用接口 loading.value = false } const handleEventsChange = (val) => { emits('change', val) } </script>
el-select懶加載(自定義指令selectLazyload)實(shí)現(xiàn)大數(shù)據(jù)量展示和搜索
需求:在一個(gè)el-form里使用el-select提供選擇用戶的下拉框,但是每次打開(kāi)彈框的時(shí)候由于數(shù)據(jù)量過(guò)大都需要加載很久才能將數(shù)據(jù)渲染出來(lái),并且頁(yè)面異常卡頓
封裝懶加載指令
在指令文件夾下新建文件 selectLazyload.js
export default { bind (el, binding) { // 獲取選擇器下的滾動(dòng)框DOM const SELECTWRAP_DOM = el.querySelector( `.el-select-dropdown__wrap` ); // 如果找到了滾動(dòng)框DOM,則添加滾動(dòng)事件監(jiān)聽(tīng)器 if (SELECTWRAP_DOM) { SELECTWRAP_DOM.addEventListener("scroll", function () { // 如果滾動(dòng)到底部,則調(diào)用傳入的回調(diào)函數(shù) const condition = SELECTWRAP_DOM.scrollHeight - SELECTWRAP_DOM.scrollTop <= SELECTWRAP_DOM.clientHeight; if (condition) { binding.value(); } }); } }, };
在main.js或directive/index.js中注冊(cè)這個(gè)自定義指令
import selectLazyLoad from './module/selectLazyLoad' Vue.directive('selectLazyLoad', selectLazyLoad)
html結(jié)構(gòu):在el-select上添加
v-selectLazyLoad="loadMore"
和 :filter-method="userFilterMethod"
<el-select v-model="transferTesterNo" filterable placeholder="請(qǐng)選擇測(cè)試人" 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結(jié)構(gòu)
// 加載更多 loadMore(){ // 如果截取的長(zhǎng)度==獲取到的所有option長(zhǎng)度將不再截取 if (this.options.length == this.userOptions?.length) return; this.userPageNum++; this.getScrollUser(); }, // 截取頁(yè)面顯示的實(shí)際option getScrollUser(){ // 過(guò)濾出前5條用戶信息 實(shí)際展示的數(shù)據(jù) options 全部數(shù)據(jù) userOptions this.options = this.userOptions.slice(0, this.userPageNum * 5); }, // 搜索功能 userFilterMethod(value){ // 手動(dòng)觸發(fā)下拉框回滾至頂部,避免觸發(fā)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)) || []; },
首次加載需要在 獲取數(shù)據(jù)的接口內(nèi)寫(xiě)上
this.userOptions = rows this.getScrollUser() // 在data 中定義變量 userOptions: [], options: [], userPageNum: 1,
這樣即可實(shí)現(xiàn) 在滾動(dòng)到底部時(shí)動(dòng)態(tài)加載后面的數(shù)據(jù),且可以搜索
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Vue項(xiàng)目設(shè)置多個(gè)靜態(tài)文件及自定義靜態(tài)文件目錄的方案詳解
本文介紹了如何在Vue項(xiàng)目中配置多個(gè)靜態(tài)文件目錄,并提供了使用Vite和Webpack實(shí)現(xiàn)的示例,通過(guò)在vite.config.ts或vue.config.js中引入相關(guān)插件和配置,可以輕松實(shí)現(xiàn)自定義靜態(tài)文件目錄,希望這些內(nèi)容對(duì)您有所幫助,感興趣的朋友一起看看吧2025-01-01在項(xiàng)目中封裝axios的實(shí)戰(zhàn)過(guò)程
這篇文章主要給大家介紹了關(guān)于如何在項(xiàng)目中封裝axios的相關(guān)資料,axios 請(qǐng)求的封裝,無(wú)非是為了方便代碼管理,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-09-09在vue項(xiàng)目中,將juery設(shè)置為全局變量的方法
今天小編就為大家分享一篇在vue項(xiàng)目中,將juery設(shè)置為全局變量的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09在vue中nextTick用法及nextTick 的原理是什么
這篇文章主要介紹了在vue中nextTick用法及nextTick 的原理是什么,Vue.js 是一個(gè)流行的前端框架,它提供了一種響應(yīng)式的數(shù)據(jù)綁定機(jī)制,使得頁(yè)面的數(shù)據(jù)與頁(yè)面的 UI 組件之間能夠自動(dòng)同步,需要的朋友可以參考下2023-04-04vue打印功能實(shí)現(xiàn)的兩種方法總結(jié)
在項(xiàng)目中,有時(shí)需要打印頁(yè)面的表格,所以下面這篇文章主要給大家介紹了關(guān)于vue打印功能實(shí)現(xiàn)的兩種方法,以及批量打印的完整代碼,需要的朋友可以參考下2021-06-06一個(gè)因@click.stop引發(fā)的bug的解決
這篇文章主要介紹了一個(gè)因@click.stop引發(fā)的bug的解決,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-01-01Vue單頁(yè)面應(yīng)用做預(yù)渲染的方法實(shí)例
vue是一個(gè)單頁(yè)面的應(yīng)用,這導(dǎo)致一些爬蟲(chóng)和百度無(wú)法搜索到,如果你想針對(duì)你應(yīng)用的其中某些頁(yè)面進(jìn)行SEO優(yōu)化,讓他們可以被爬蟲(chóng)和百度搜索到,你可以進(jìn)行預(yù)渲染操作,下面這篇文章主要給大家介紹了關(guān)于Vue單頁(yè)面應(yīng)用做預(yù)渲染的相關(guān)資料,需要的朋友可以參考下2021-10-10