vue3 el-select懶加載以及自定義指令方式
vue3 el-select懶加載以及自定義指令
要求:自定義搜索、自定義指令,滾動懶加載每次展示10條數(shù)據(jù)
在element-plus中,el-select的選項框是使用popper.js生成的,不在body中,無法直接獲取,這時需要巧妙地使用popper-class屬性來獲取到dom并掛載到el-select進行監(jiān)聽來實現(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語法糖中,以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給一個參數(shù)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 獲取元素內(nèi)容高度(只讀)
* scrollTop 獲取或者設置元素的偏移值,常用于, 計算滾動條的位置, 當一個元素的容器沒有產(chǎn)生垂直方向的滾動條, 那它的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和函數(shù)掛載到el-select上,實例銷毀時好處理
el.selectDomInfo = selectDom
el.selectLoadMore = loadMores
// 監(jiān)聽滾動事件
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 = () => {
// 數(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
})
}
// 自定義過濾函數(shù)
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)
}
})
}
// 下拉框隱藏時,重置分頁已經(jīng)過濾得到的列表
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)實現(xiàn)大數(shù)據(jù)量展示和搜索
需求:在一個el-form里使用el-select提供選擇用戶的下拉框,但是每次打開彈框的時候由于數(shù)據(jù)量過大都需要加載很久才能將數(shù)據(jù)渲染出來,并且頁面異??D
封裝懶加載指令
在指令文件夾下新建文件 selectLazyload.js
export default {
bind (el, binding) {
// 獲取選擇器下的滾動框DOM
const SELECTWRAP_DOM = el.querySelector(
`.el-select-dropdown__wrap`
);
// 如果找到了滾動框DOM,則添加滾動事件監(jiān)聽器
if (SELECTWRAP_DOM) {
SELECTWRAP_DOM.addEventListener("scroll", function () {
// 如果滾動到底部,則調(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中注冊這個自定義指令
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條用戶信息 實際展示的數(shù)據(jù) options 全部數(shù)據(jù) userOptions
this.options = this.userOptions.slice(0, this.userPageNum * 5);
},
// 搜索功能
userFilterMethod(value){
// 手動觸發(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)寫上
this.userOptions = rows this.getScrollUser() // 在data 中定義變量 userOptions: [], options: [], userPageNum: 1,
這樣即可實現(xiàn) 在滾動到底部時動態(tài)加載后面的數(shù)據(jù),且可以搜索
總結
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
vue中為什么在組件內(nèi)部data是一個函數(shù)而不是一個對象
這篇文章主要介紹了vue中為什么在組件內(nèi)部data是一個函數(shù)而不是一個對象,本文通過示例代碼給大家講解的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04
vue2.0基于vue-cli+element-ui制作樹形treeTable
這篇文章主要介紹了vue2.0基于vue-cli+element-ui制作樹形treeTable,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-04-04
詳解vue中使用express+fetch獲取本地json文件
本篇文章主要介紹了詳解vue中使用express+fetch獲取本地json文件,非常具有實用價值,需要的朋友可以參考下2017-10-10
Vue3封裝全局自定義指令實現(xiàn)按鈕權限控制功能實例
在Vue應用中自定義指令是一種強大的功能,可以用于封裝DOM操作邏輯,這篇文章主要介紹了Vue3封裝全局自定義指令實現(xiàn)按鈕權限控制功能的相關資料,需要的朋友可以參考下2025-07-07
前端VUE3項目部署到linux服務器(CentOS?7)完整步驟
這篇文章主要介紹了前端VUE3項目部署到linux服務器(CentOS?7)的相關資料,包括項目打包、連接服務器、安裝和配置Nginx、上傳文件以及配置Nginx,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2026-01-01

