vue如何實現(xiàn)el-select下拉選項的懶加載
下拉選擇是常用的用戶交互選擇的操作;常用固定選擇項或者動態(tài)渲染選擇項。
實際項目中存在數(shù)據(jù)量大,一次性渲染很多數(shù)據(jù)會造成下拉卡頓的問題,通過滾動懶加載,逐步增加下拉選項。
滾動加載的核心邏輯
通過監(jiān)聽容器的滾動事件,滾到最底部時,執(zhí)行加載數(shù)據(jù)函數(shù)。
interface IScrollOption { distance: number; // 觸發(fā)loadData事件的滾軸距底部的距離 loadData: () => void; // 數(shù)據(jù)加載函數(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ù)據(jù)
由于el-select 組件并沒有提供內(nèi)部數(shù)據(jù)滾動的事件或者自定義內(nèi)部滾動容器DOM元素 . 只能通過F12 查看頁面結(jié)構(gòu)獲知滾動的容器DOM選擇器 .
可以通過自定義指令的方式,提取共用邏輯,不局限于select,也可用于其他列表懶加載渲染的UI組件.
/** * 定義懶加載數(shù)據(jù)列表的指令 * 可通過滾動懶加載來減少一次性渲染大量數(shù)據(jù)的性能卡頓 */ import Vue from "vue"; import { throttle } from "lodash"; export interface ILazyProps { loadData: () => void; // 數(shù)據(jù)加載函數(shù) distance: number; // 觸發(fā)函數(shù)調(diào)用的滾動距離 scrollBody?: string; // 置頂滾動容器 , 不指定則為指令綁定元素 callback: (fn: () => void) => void; // 自定義回調(diào)邏輯,可用于適時銷毀監(jiān)聽事件 } Vue.directive("lazy-load", { /** * el - 指令所綁定的元素DOM * binding - 傳入指令的其他附帶參數(shù) * name - 指令名 * value - 指令綁定的值 * oldValue - 綁定的前一個值 * expression - 指令綁定的字符串形式的表達(dá)式 * arg - 傳給指令的參數(shù) * modifiers - 指令修飾符的對象 * vnode * oldVnode */ inserted: (el, binding) => { // 獲取scroll 滾動的容器元素,由參數(shù)傳入 // 如果沒有傳入,則默認(rèn)綁定指令的元素自己 // 獲取懶加載處理函數(shù) , 以及其他參數(shù) const { loadData, distance, scrollBody, callback } = binding.value as ILazyProps; let scrollContainer = el; if (scrollBody) { scrollContainer = el.querySelector(scrollBody) || el; } // 滾動事件監(jiān)聽 const scroll = throttle( handleScroll.bind(null, scrollContainer, { distance, loadData }), 500 ); scrollContainer.addEventListener("scroll", scroll); // 回調(diào)時 返回事件銷毀函數(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 滾動容器的DOM元素的class選擇器 callback: (fn: () => void) => { // 這里是在組件銷毀前, 移除監(jiān)聽事件. this.$once("hook:beforeDestroy", () => fn()); }, }; loadData(): void { this.data = this.data.concat( new Array(5).fill({ id: "1009", name: "雙十一", }) ); } }
Element-plus 正在新增的一個組件 el-select-v2 虛擬化列表下拉選擇器 . 虛擬列表與懶加載不同的是,虛擬列表渲染的DOM節(jié)點固定,通過滾動的位置計算需要展示的數(shù)據(jù).
Element 指令v-infinite-scroll
element 也提供了用于懶加載數(shù)據(jù)的指令v-infinite-scroll , 缺陷在于它只監(jiān)聽指令綁定的DOM元素的滾動事件.
infinite-scroll-disabled
是否禁用加載,如果是分頁數(shù)據(jù) , 則可以通過計算屬性pageSize*pageNum>=totalinfinite-scroll-delay
節(jié)流加載,默認(rèn) 200msinfinite-scroll-distance
觸發(fā)加載的滾動距離閥值 .infinite-scroll-immediate
是否立即執(zhí)行加載函數(shù),需要撐滿容器元素;否則手動請求一次數(shù)據(jù).
整個數(shù)據(jù)列表頁不需要分頁操作時, 需要通過頁面滾動來加載數(shù)據(jù)
<div v-infinite-scroll="loadData" infinite-scroll-disabled="disabled" infinite-scroll-delay="delay"> <table :showPagination="false" :tableOption="tableOption" :tableColumns="tableColumns" ></table> </div>
頁面滾動時調(diào)用loadData函數(shù),定義請求加載數(shù)據(jù)的邏輯.
直接貼源碼
export default { name: 'InfiniteScroll', inserted(el, binding, vnode) { // 綁定的回調(diào)函數(shù) const cb = binding.value; // 當(dāng)前組件實例引用 const vm = vnode.context; // only include vertical scroll // 滾動容器DOM元素 const container = getScrollContainer(el, true); // 獲取指令需要的參數(shù) delay distance immediate disabled const { delay, immediate } = getScrollOptions(el, vm); // 滾動事件處理函數(shù),節(jié)流 const onScroll = throttle(delay, handleScroll.bind(el, cb)); // 將額外的計算屬性綁定到el上,在unbind 可用于移除監(jiān)聽函數(shù) el[scope] = { el, vm, container, onScroll }; if (container) { container.addEventListener('scroll', onScroll); if (immediate) { // 容器內(nèi)元素發(fā)生節(jié)點變更時觸發(fā)執(zhí)行 // MutationObserver API 功能調(diào)用 const observer = el[scope].observer = new MutationObserver(onScroll); observer.observe(container, { childList: true, subtree: true }); // 初始調(diào)用一次滾動加載函數(shù) onScroll(); } } }, unbind(el) { // 移除滾動事件 const { container, onScroll } = el[scope]; if (container) { container.removeEventListener('scroll', onScroll); } } };
MutationObserver
監(jiān)視對DOM樹更改的能力
實例構(gòu)造函數(shù)接收一個回調(diào)函數(shù),為DOM發(fā)生變化時需要執(zhí)行的回調(diào)
observe(target,[option])
配置需要監(jiān)聽的DOM元素,以及DOM變更的配置項disconnect()
停止接收DOM變化的通知takeRecords()
獲取未被回調(diào)處理的通知
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue-router實現(xiàn)webApp切換頁面動畫效果代碼
本篇文章主要介紹了vue實現(xiàn)app頁面切換效果實例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-05-05vue中el-table實現(xiàn)穿梭框(數(shù)據(jù)可以上移下移)
本文主要介紹了vue中el-table實現(xiàn)穿梭框(數(shù)據(jù)可以上移下移),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06Vue中使用create-keyframe-animation與動畫鉤子完成復(fù)雜動畫
這篇文章主要介紹了Vue中使用create-keyframe-animation與動畫鉤子完成復(fù)雜動畫,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-04-04vue中v-if和v-for一起使用的弊端及解決辦法(同時使用 v-if 和 v-for不
當(dāng) v-if 和 v-for 同時存在于一個元素上的時候,v-if 會首先被執(zhí)行,這篇文章主要介紹了vue中v-if和v-for一起使用的弊端及解決辦法,需要的朋友可以參考下2023-07-07vue-router 實現(xiàn)導(dǎo)航守衛(wèi)(路由衛(wèi)士)的實例代碼
這篇文章主要介紹了vue-router 實現(xiàn)導(dǎo)航守衛(wèi)(路由衛(wèi)士)的實例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-09-09