Boost Transfer Component Performance with Lazy Loading and Infinite Scroll
Learn how to eliminate page lag when handling large datasets in Element UI's transfer component by applying lazy loading, infinite scroll, and pagination techniques, separating display from logic, and adding custom scroll handling for both downward and upward navigation.
Element Transfer Component Performance Optimization
Chen Jianbo: A Hearthstone player delayed by coding
Background
When the transfer component processes large amounts of data, rendering too many DOM nodes causes page lag. The goal is to improve performance while keeping the component's original logic largely unchanged.
Solution Idea
Apply lazy loading using an InfiniteScroll component. Copy the original component from packages/transfer (or repackage it as a private library) and add infinite‑scroll attributes.
v-infinite-scroll="pageDown"
:infinite-scroll-immediate="false"Insert these attributes into the el-checkbox-group element:
<el-checkbox-group
v-show="!hasNoMatch && data.length > 0"
v-model="checked"
:size="size"
:class="{ 'is-filterable': filterable }"
class="el-transfer-panel__list"
v-infinite-scroll="pageDown"
:infinite-scroll-immediate="false"
>
<el-checkbox
class="el-transfer-panel__item"
:label="item[keyProp]"
:disabled="item[disabledProp]"
:key="item[keyProp]"
v-for="item in filteredData"
>
<option-content :option="item"></option-content>
</el-checkbox>
</el-checkbox-group>Define pagination data in data:
pageSize: 20 // items per page
showData: [] // data displayed on the current page
filteredData: [] // data after filtering, used for renderingUse v-for="item in showData" to render the visible items. v-for="item in showData"> Watchers handle data changes:
data(data) {
const checked = [];
this.showData = data.slice(0, this.pageSize);
const filteredDataKeys = this.filteredData.map(item => item[this.keyProp]);
this.checked.forEach(item => {
if (filteredDataKeys.indexOf(item) > -1) {
checked.push(item);
}
});
this.checkChangeByUser = false;
this.checked = checked;
},
filteredData(filteredData) {
this.showData = filteredData.slice(0, this.pageSize);
}Initialize the display count (e.g., 20 items).
Scrolling Down
Add a method that loads more items when the user reaches the bottom:
pageDown() {
const l = this.showData.length;
const totalLength = this.filteredData.length;
if (l < totalLength) {
this.showData = this.filteredData.slice(0, l + this.pageSize > totalLength ? totalLength : l + this.pageSize);
}
}This increases the displayed data length by 20 each time the user scrolls down, up to the maximum length, effectively solving the lag caused by large data sets.
New Issue
Manually scrolling to the end of the list and then performing a search still causes lag.
Advanced Optimization
During scrolling, the items above the viewport are not visible and do not affect user experience, so only the current page of 20 items needs to be shown. Add a ref="scrollContainer" to el-checkbox-group for scroll control and define a current page index:
data() {
...
curIndex: 1
}Modify pageDown to use curIndex:
pageDown() {
const totalLength = this.filteredData.length;
if ((this.curIndex * this.pageSize) < totalLength) {
this.curIndex++;
const targetLength = this.curIndex * this.pageSize;
const endPoint = targetLength > totalLength ? totalLength : targetLength;
const startPoint = endPoint - this.pageSize > 0 ? endPoint - this.pageSize : 0;
this.showData = this.filteredData.slice(startPoint, endPoint);
this.$refs.scrollContainer.$el.scrollTop = "1px"; // scroll to top of next page
}
}Since the built‑in InfiniteScroll directive only supports downward scrolling, add upward scrolling support:
mounted() {
this.$refs.scrollContainer.$el.addEventListener('scroll', this.pageUp);
},
beforeDestroy() {
this.$refs.scrollContainer.$el.removeEventListener('scroll', this.pageUp);
}Implement pageUp to load the previous page when the scroll reaches the top:
pageUp(e) {
if (e.target.scrollTop === 0 && this.curIndex > 1) {
this.curIndex--;
const endPoint = this.curIndex * this.pageSize;
const startPoint = (this.curIndex - 1) * this.pageSize;
this.showData = this.filteredData.slice(startPoint, endPoint);
const el = this.$refs.scrollContainer.$el;
el.scrollTop = el.scrollHeight - el.clientHeight - 1; // scroll to bottom of previous page
}
}Reset the scroll position and page index whenever the data changes to avoid unexpected pagination:
initScroll() {
this.curIndex = 1;
this.$refs.scrollContainer.$el.scrollTop = 0;
}Call initScroll in the relevant watchers:
data() {
...
this.initScroll();
...
},
filteredData(filteredData) {
...
this.initScroll();
}With these adjustments, the transfer component handles large data sets efficiently, eliminating lag while preserving the original component logic.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
WeDoctor Frontend Technology
Official WeDoctor Group frontend public account, sharing original tech articles, events, job postings, and occasional daily updates from our tech team.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
