vue如何實(shí)現(xiàn)el-select下拉選項(xiàng)的懶加載
下拉選擇是常用的用戶交互選擇的操作;常用固定選擇項(xiàng)或者動(dòng)態(tài)渲染選擇項(xiàng)。
實(shí)際項(xiàng)目中存在數(shù)據(jù)量大,一次性渲染很多數(shù)據(jù)會(huì)造成下拉卡頓的問(wèn)題,通過(guò)滾動(dòng)懶加載,逐步增加下拉選項(xiàng)。
滾動(dòng)加載的核心邏輯
通過(guò)監(jiān)聽(tīng)容器的滾動(dòng)事件,滾到最底部時(shí),執(zhí)行加載數(shù)據(jù)函數(shù)。
interface IScrollOption {
distance: number; // 觸發(fā)loadData事件的滾軸距底部的距離
loadData: () => void; // 數(shù)據(jù)加載函數(shù)
}
/**
* 處理容器滾動(dòng)事件 ; 滾動(dòng)到底部時(shí),執(zhí)行處理函數(shù)
* @param dom
* @param option
*/
function handleScroll(dom: Element, option: IScrollOption) {
//
const scrollBottom = dom.scrollTop + dom.clientHeight;
if (dom.scrollHeight - scrollBottom <= option.distance) {
// 數(shù)據(jù)加載
option.loadData();
}
}
在vue中處理數(shù)據(jù)懶加載
使用Element作為UI組件,常用下拉select 方式為
<el-select v-model="selectData"> ? <el-option v-for="item in data" :key="item.id" value="item.id" :label="item.name"></el-option> </el-select>
data 為渲染數(shù)據(jù),存在大批量數(shù)據(jù)時(shí),防止下拉卡頓,采用懶加載的方式逐步增加數(shù)據(jù)
由于el-select 組件并沒(méi)有提供內(nèi)部數(shù)據(jù)滾動(dòng)的事件或者自定義內(nèi)部滾動(dòng)容器DOM元素 . 只能通過(guò)F12 查看頁(yè)面結(jié)構(gòu)獲知滾動(dòng)的容器DOM選擇器 .
可以通過(guò)自定義指令的方式,提取共用邏輯,不局限于select,也可用于其他列表懶加載渲染的UI組件.
/**
* 定義懶加載數(shù)據(jù)列表的指令
* 可通過(guò)滾動(dòng)懶加載來(lái)減少一次性渲染大量數(shù)據(jù)的性能卡頓
*/
import Vue from "vue";
import { throttle } from "lodash";
export interface ILazyProps {
loadData: () => void; // 數(shù)據(jù)加載函數(shù)
distance: number; // 觸發(fā)函數(shù)調(diào)用的滾動(dòng)距離
scrollBody?: string; // 置頂滾動(dòng)容器 , 不指定則為指令綁定元素
callback: (fn: () => void) => void; // 自定義回調(diào)邏輯,可用于適時(shí)銷毀監(jiān)聽(tīng)事件
}
Vue.directive("lazy-load", {
/**
* el - 指令所綁定的元素DOM
* binding - 傳入指令的其他附帶參數(shù)
* name - 指令名
* value - 指令綁定的值
* oldValue - 綁定的前一個(gè)值
* expression - 指令綁定的字符串形式的表達(dá)式
* arg - 傳給指令的參數(shù)
* modifiers - 指令修飾符的對(duì)象
* vnode
* oldVnode
*/
inserted: (el, binding) => {
// 獲取scroll 滾動(dòng)的容器元素,由參數(shù)傳入
// 如果沒(méi)有傳入,則默認(rèn)綁定指令的元素自己
// 獲取懶加載處理函數(shù) , 以及其他參數(shù)
const { loadData, distance, scrollBody, callback } =
binding.value as ILazyProps;
let scrollContainer = el;
if (scrollBody) {
scrollContainer = el.querySelector(scrollBody) || el;
}
// 滾動(dòng)事件監(jiān)聽(tīng)
const scroll = throttle(
handleScroll.bind(null, scrollContainer, { distance, loadData }),
500
);
scrollContainer.addEventListener("scroll", scroll);
// 回調(diào)時(shí) 返回事件銷毀函數(shù)
callback(() => {
scrollContainer.removeEventListener("scroll", scroll);
});
},
});
在vue組件中使用指令 v-lazy-load
視圖,只需要添加指令.綁定指令需要的屬性值.
<el-select v-model="selectData" v-lazy-load="lazyOption"> ? <el-option v-for="item in data" :key="item.id" value="item.id" :label="item.name"></el-option> </el-select>
腳本部分 , 包括初始化layzOption 定義數(shù)據(jù)加載函數(shù)
import { ILazyProps } from "@/directives/lazyLoad";
export default class extends Vue {
lazyOption: ILazyProps = {
loadData: this.loadData,
distance: 20,
scrollBody: ".el-scrollbar__wrap", // 為el-select 滾動(dòng)容器的DOM元素的class選擇器
callback: (fn: () => void) => {
// 這里是在組件銷毀前, 移除監(jiān)聽(tīng)事件.
this.$once("hook:beforeDestroy", () => fn());
},
};
loadData(): void {
this.data = this.data.concat(
new Array(5).fill({
id: "1009",
name: "雙十一",
})
);
}
}
Element-plus 正在新增的一個(gè)組件 el-select-v2 虛擬化列表下拉選擇器 . 虛擬列表與懶加載不同的是,虛擬列表渲染的DOM節(jié)點(diǎn)固定,通過(guò)滾動(dòng)的位置計(jì)算需要展示的數(shù)據(jù).
Element 指令v-infinite-scroll
element 也提供了用于懶加載數(shù)據(jù)的指令v-infinite-scroll , 缺陷在于它只監(jiān)聽(tīng)指令綁定的DOM元素的滾動(dòng)事件.
infinite-scroll-disabled是否禁用加載,如果是分頁(yè)數(shù)據(jù) , 則可以通過(guò)計(jì)算屬性pageSize*pageNum>=totalinfinite-scroll-delay節(jié)流加載,默認(rèn) 200msinfinite-scroll-distance觸發(fā)加載的滾動(dòng)距離閥值 .infinite-scroll-immediate是否立即執(zhí)行加載函數(shù),需要撐滿容器元素;否則手動(dòng)請(qǐng)求一次數(shù)據(jù).
整個(gè)數(shù)據(jù)列表頁(yè)不需要分頁(yè)操作時(shí), 需要通過(guò)頁(yè)面滾動(dòng)來(lái)加載數(shù)據(jù)
<div v-infinite-scroll="loadData" infinite-scroll-disabled="disabled" infinite-scroll-delay="delay">
<table
:showPagination="false"
:tableOption="tableOption"
:tableColumns="tableColumns"
></table>
</div>
頁(yè)面滾動(dòng)時(shí)調(diào)用loadData函數(shù),定義請(qǐng)求加載數(shù)據(jù)的邏輯.
直接貼源碼
export default {
name: 'InfiniteScroll',
inserted(el, binding, vnode) {
// 綁定的回調(diào)函數(shù)
const cb = binding.value;
// 當(dāng)前組件實(shí)例引用
const vm = vnode.context;
// only include vertical scroll
// 滾動(dòng)容器DOM元素
const container = getScrollContainer(el, true);
// 獲取指令需要的參數(shù) delay distance immediate disabled
const { delay, immediate } = getScrollOptions(el, vm);
// 滾動(dòng)事件處理函數(shù),節(jié)流
const onScroll = throttle(delay, handleScroll.bind(el, cb));
// 將額外的計(jì)算屬性綁定到el上,在unbind 可用于移除監(jiān)聽(tīng)函數(shù)
el[scope] = { el, vm, container, onScroll };
if (container) {
container.addEventListener('scroll', onScroll);
if (immediate) {
// 容器內(nèi)元素發(fā)生節(jié)點(diǎn)變更時(shí)觸發(fā)執(zhí)行
// MutationObserver API 功能調(diào)用
const observer = el[scope].observer = new MutationObserver(onScroll);
observer.observe(container, { childList: true, subtree: true });
// 初始調(diào)用一次滾動(dòng)加載函數(shù)
onScroll();
}
}
},
unbind(el) {
// 移除滾動(dòng)事件
const { container, onScroll } = el[scope];
if (container) {
container.removeEventListener('scroll', onScroll);
}
}
};
MutationObserver監(jiān)視對(duì)DOM樹(shù)更改的能力
實(shí)例構(gòu)造函數(shù)接收一個(gè)回調(diào)函數(shù),為DOM發(fā)生變化時(shí)需要執(zhí)行的回調(diào)
observe(target,[option])配置需要監(jiān)聽(tīng)的DOM元素,以及DOM變更的配置項(xiàng)disconnect()停止接收DOM變化的通知takeRecords()獲取未被回調(diào)處理的通知
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
不同場(chǎng)景下Vue中虛擬列表實(shí)現(xiàn)
虛擬列表用來(lái)解決大數(shù)據(jù)量數(shù)據(jù)渲染問(wèn)題,由于一次性渲染性能低,所以誕生了虛擬列表渲染,下面我們就來(lái)學(xué)習(xí)一下不同場(chǎng)景下Vue中虛擬列表是如何實(shí)現(xiàn)的吧2023-10-10
vue跳轉(zhuǎn)頁(yè)面并且實(shí)現(xiàn)參數(shù)傳遞接受示例
這篇文章主要為大家介紹了vue跳轉(zhuǎn)頁(yè)面并且實(shí)現(xiàn)參數(shù)傳遞接受示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
vue-router3.x和vue-router4.x相互影響的問(wèn)題分析
這篇文章主要介紹了vue-router3.x和vue-router4.x相互影響的問(wèn)題分析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04
Vue3+TypeScript封裝axios并進(jìn)行請(qǐng)求調(diào)用的實(shí)現(xiàn)
這篇文章主要介紹了Vue3+TypeScript封裝axios并進(jìn)行請(qǐng)求調(diào)用的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
vue.js+elementUI實(shí)現(xiàn)點(diǎn)擊左右箭頭切換頭像功能(類似輪播圖效果)
這篇文章主要介紹了vue.js+elementUI實(shí)現(xiàn)點(diǎn)擊左右箭頭切換頭像功能(類似輪播圖),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09
Vue3中按需引入ECharts詳細(xì)步驟(一看就會(huì))
新項(xiàng)目采用Vue3作為前端項(xiàng)目框架,避免不了要使用echarts,這篇文章主要給大家介紹了關(guān)于Vue3中按需引入ECharts的相關(guān)資料,需要的朋友可以參考下2023-09-09
詳解webpack編譯多頁(yè)面vue項(xiàng)目的配置問(wèn)題
本篇文章主要介紹了詳解webpack編譯多頁(yè)面vue項(xiàng)目的配置問(wèn)題,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
Vue的v-model的幾種修飾符.lazy,.number和.trim的用法說(shuō)明
這篇文章主要介紹了Vue的v-model的幾種修飾符.lazy,.number和.trim的用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08
Vue3計(jì)算屬性computed和監(jiān)聽(tīng)屬性watch區(qū)別解析
計(jì)算屬性適用于對(duì)已有的數(shù)據(jù)進(jìn)行計(jì)算,派生新的數(shù)據(jù),并在模板中使用;而監(jiān)聽(tīng)屬性適用于監(jiān)聽(tīng)數(shù)據(jù)的變化,并執(zhí)行一些特定的操作,根據(jù)具體的需求和場(chǎng)景,選擇適合的機(jī)制這篇文章主要介紹了Vue3計(jì)算屬性computed和監(jiān)聽(tīng)屬性watch,需要的朋友可以參考下2024-02-02

