preface
Long list problem in the project has encountered many times, there are also a lot of excellent articles in the community, this time finally in b station big guy’s video entry, the following is a learning summary, beginners recommend to see this video, ensure that you can understand!!
To prepare
1. Use Node to build the service, simulate the effect of the front and back end interface request (back-end code directly use the big guy)
2. Start with a few simple styles for the front end
Analysis of the
Simple answer analysis a ha
For example, is, usually we use equipment data browse news, slide for us to see things in the current equipment visual area for us is the “effective”, and other places we can’t see them anyway, we are not concerned about whether visual area outside of the data load out, as long as the sliding to the visible area, Just show us what’s in the viewable area.
The text is too boring. Let’s try the last picture.
Due to render a page need to parse the data to generate a dom tree, cssom then dom tree and the tree cssom synthesis render tree tree will end, the final render generated but interface (this process is not understood recommend watching this one), if the data quantity is big, the process can be slow, the performance is also low, assuming that no matter how many of the data, We were capricious and just loaded a few pieces of data in the viewable area and the performance was optimized. To achieve the above said “capricious”, that nature requires us to deal with the line.
Do you want a bag?
The core problem here is to find the data that should be rendered on the screen in the returned data.
Wide above code to try a ha
Initialization – first simulate the data (see code – appendix 1)
There is nothing to say here, just request the data from the background and render it to the page.
Step 2 – Several important variables need to be defined
- OneItemHeight: Height of each item.
- ContainerHeight: Gets the height of the roll.
- MaxContainerSize: indicates the maximum number of data items that can be displayed on the screen.
- containerHeight / oneItemHeight = maxContainerSize
- During continuous scrolling, you need to know where the data displayed at the top of the scroll container is in all the data
- Similarly, you need to know where the data displayed at the bottom of the scroll container is in all the data
Calculate maxContainerSize (note the boundary case, the top and bottom are exposed a little bit)
getContainSize() {
debugger
// step 1: Calculate the height of the container
let height = this.$refs.scrollContainer.offsetHeight;
//3. Step 2: Height of the whole outer box/height of each = maximum number of bars that can be loaded on each screen
let num = height / this.oneItemHeight;
//4. Step 3: Note that if a little bit of the top is shown and a little bit of the bottom is shown, the current amount is the integer +2
let maxNum = Math.floor(num) + 2;
this.maxContainerSize = maxNum;
console.log(this.maxContainerSize)
}
Copy the code
Calculate startIndex
StartIndex starts at 0, and the value of startIndex changes when scrolling. The pseudo-code is computed as follows
StartIndex = Number of data items to be rolled out -1; Number of data items to be rolled out = Height of data items to be rolled out/height of each data itemCopy the code
// Calculate the data to roll out
setStartIndex() {
let scrollTop = this.$refs.scrollContainer.scrollTop;// Current roll out height
let currentIndex = Math.floor(
this.$refs.scrollContainer.scrollTop / this.oneItemHeight // The number of pieces of data to roll out
);
if (currentIndex == this.startIndex) {
return;
}
this.startIndex = currentIndex;
console.log(currentIndex, "= = = = = = =");
},
// Count startIndex while listening to the scroll method
handleScroll() {
this.setStartIndex();
}
Copy the code
From startIndex we can calculate endIndex using the calculated property
- EndIndex: startIndex + The maximum number of entries in the container (however, the value of endIndex is the data length -1 if the display is the last screen and the last screen contains less than the entire screen)
endIndex() {
let endIndex = this.startIndex + this.maxContainerSize; //9 Step 9: Note that the bottom of the container may be empty, so we need to make a judgment
if (endIndex > this.listData.length) {// Consider special cases: the last screen of data does not cover the entire screen
endIndex = this.allDataList.length - 1; // At this point, the scroll has reached the bottom
}
return endIndex;
},
Copy the code
- Check out the GIF below to get a feel for it
- Let’s see: To illustrate the change in startIndex and endIndex, I’m using watch to listen on a computed cache
StartIndex and endIndex are calculated, and then go to the request of the data inside the data can be intercepted
Now that only 8 pieces of data are displayed on the page, we can also see that the page can always display the maximum number of pieces of data on the page, and only one piece of data can be rolled out
//10 Step 10: Define an arraylist element to display from the retrieved array
showDataList() {
return this.listData.slice(this.startIndex,this.endIndex)
},
Copy the code
To solve the above problem, we need to spread out the height of the roll
Add a box to the scrolllist, and use the padding of the box to expand the scrollTop of the outermost box
Let’s try out the padding
The following steps are required:
- Each scroll to the bottom of the need to request a data, the request out of the old and new data added
- Computes the padding-spread scrollTop
// Count startIndex while listening to the scroll method
async handleScroll() {
this.setStartIndex();
StartIndex + contentSize > data.length-1
console.log(
this.startIndex,
this.maxContainerSize,
this.showDataList.length
);
if (
this.startIndex + this.maxContainerSize >=
this.listData.length - 1
) {
console.log("Rolled to the bottom.");
// Append data
let request = await this.getListData(20);
this.listData = [...request, ...this.listData]; // rerequest data, new and old data append
console.log(this.listData); }}Copy the code
The padding to calculate
//11 Step 11: You need to define a height for the upper blank
topBlankFill() {
return this.startIndex * this.oneItemHeight;
},
//12 Step 12: You need to define the height of the whitespace
bottomBlankFill() {
return (this.listData.length - this.endIndex) * this.oneItemHeight;
}
Copy the code
See what happens when you keep pulling data down, but the DOM on the right is always only eight data pieces
Here the core code of virtual scrolling has been completed, in fact, it is not too difficult to look like, haha (this step code is attached below -3)
To optimize the
Finished, in fact, has not finished, there are a lot of more important places not optimized
Optimization 1: optimizing frequent rolling events triggered by throttling and anti-shaking
Use the principle of anti-shake: only trigger the scroll function logic every 500s
// Count startIndex while listening to the scroll method
handleScroll() {
this.debounce(this.scrollFun, 500);
},
debounce(fn, delay) {
clearTimeout(this.isScrollStatus);
this.isScrollStatus = setTimeout(function() {
fn();
}, delay);
},
async scrollFun() {
console.log("Rolling.");
this.setStartIndex();
if (this.startIndex + this.maxContainerSize >= this.listData.length - 1) {
// Append data
let request = await this.getListData(20);
this.listData = [...request, ...this.listData]; }}Copy the code
Optimization 2 uses requestAnimationFrame to optimize the animation
MDN is explained as follows:
You want to execute an animation and ask the browser to call the specified callback function to update the animation before the next redraw. This method takes as an argument a callback function that performs the requestAnimationFrame comparison before the browser's next redrawsetTimeoutEach render of his animation was consistent, and he had to wait until this render was complete before rendering the next animation, whilesetTimeoutAfter 1000ms, regardless of whether the last animation has been rendered or not, it will be re-renderedCopy the code
RequestAnimationFrame (requestAnimationFrame) is used to render each animation in a consistent manner, and it must wait until the render is complete before rendering the next animation. SetTimeout will re-render after 1000ms regardless of whether the previous animation has been rendered.
requestF() {
let requestAnimationFrame =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
// Browser anti-vibration optimization: according to the browser FPS using recursive method, queue call requestAnimationFrame method to achieve optimization
let fps = 30;
let interval = 1000 / fps;
let then = Date.now();
requestAnimationFrame(() = > {
let now = Date.now();
let delta = now - then;
then = now;
this.scrollFun();
if (delta >= interval) {
requestAnimationFrame(arguments.callee); }}); },Copy the code
Optimization 3: Need to add a screen buffer at the top and bottom
Simulation are not: imagine a ha, if the second request network is slow, but we have to scroll to the bottom, but the data haven’t request, this time we may see a blank area below, so we need to set aside a separately on top and the bottom screen, to recount endIndex to solve this problem
endIndex() {
let endIndex = this.startIndex + this.containSize * 2; //9 Step 9: Reserve a buffer for the bottom
if (endIndex > this.allDataList.length) {
endIndex = this.allDataList.length - 1;
}
return endIndex;
}
Copy the code
ShowList: Reserved at the top and bottom
//10 Step 10: Define an arraylist element to display from the retrieved array
showDataList() {
let startIndex = 0;
let endIndex = 0;
if (this.startIndex <= this.containSize) {
// It has not been rolled out yet
startIndex = 0;
} else {
startIndex = this.startIndex - this.containSize * 2; // Need to subtract roll two screen data
}
return this.listData.slice(startIndex, this.endIndex);
},
Copy the code
TopPadding: Also recalculated, subtracting the reserved screen
//11 Step 11: You need to define a height for the upper blank
topBlankFill() {
//20. Step 20: The upper and lower padding is also required
// Step 19: Set the front and rear buffers
let paddingTop = 0;
if (this.startIndex > this.maxContainerSize) {
// Have already rolled out a screen
// Fill the space only when the current scroll position is larger than the screen capacity
paddingTop =
(this.startIndex - this.maxContainerSize) * this.oneItemHeight;
console.log(this.startIndex, this.maxContainerSize,paddingTop);
}
return paddingTop;
},
Copy the code
4: There are still some details to deal with, I recommend to watch the video, very detailed
code
Attachment -1: initialization
<template>
<div class="news-box">
<! Step 7: Listen for scroll events -->
<div class="scroll-container" ref="scrollContainer">
<div v-for="(item, index) in listData" :key="index">
<router-link class="one-new" :to=" '/article/' + item.title + '/'+ item.reads + '/'+ item.from + '/'+ item.date + '/'+ item.image ">
<! -- Headlines, comments, sources -->
<div class="new-left">
<h3>{{ item.title }}</h3>
<div>
<p>
<img src=".. /assets/icons/msg.png" alt="Evaluation" />
<span>{{ item.reads }}</span>
<span>{{ item.from }}</span>
</p>
<h4>{{ item.date }}</h4>
</div>
</div>
<! -- Picture on the right side of news -->
<div class="new-right">
<! -- <img :src="imgsList[oneItem.image]" alt="PIC" /> -->
</div>
</router-link>
</div>
</div>
</div>
</template>
<script>
// Introduce the prepared news image related information
import imgsList from ".. /components/newsImgs.js";
import { setTimeout.clearTimeout } from "timers";
export default {
data() {
return {
listData: []}; },created() {
let num = this.getListData(20);
console.log(num, "= = = = = = = = =");
},
methods: {
getListData(num) {
return this.$axios
.get("http://localhost:4000/data? num=" + num)
.then(res= > {
this.listData = res.data.list;
})
.catch(() = > {
this.msg = "Request failed please try again later...";
return false; }); }}};</script>
<style lang="scss" scoped>
.news-box {
width: 100%;
max-width: 800px;
height: 100%;
.scroll-container {
width: 100%;
height: 100%;
overflow-y: auto;
.one-new {
text-decoration: none;
display: block;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
border-bottom: 1px solid #ddd;
padding: 14px 10px 5px;
.new-left {
height: 80px;
position: relative;
h3 {
padding: 0;
margin: 0;
font-size: 16px;
text-align: justify;
color: # 555;
}
div {
position: absolute;
width: 100%;
bottom: 10px;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
align-items: center;
p {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
align-items: center;
img {
height: 16px;
}
span {
font-size: 12px;
color: # 555;
margin-left: 3px;
margin-right: 3px; }}h4 {
font-size: 12px;
color: # 888; }}}.new-right {
margin-left: 10px;
img {
height: 68px; }}}.msg h2 {
font-size: 18px;
text-align: center;
color: # 666;
padding-top: 58px; }}}</style>
Copy the code
Attachment -2 calculates startIndex during scrolling
<template>
<div class="news-box">
<! Step 7: Listen for scroll events -->
<div class="scroll-container" ref="scrollContainer" @scroll.passive="handleScroll">
<div v-for="(item, index) in showDataList" :key="index">
<router-link class="one-new" :to=" '/article/' + item.title + '/'+ item.reads + '/'+ item.from + '/'+ item.date + '/'+ item.image ">
<! -- Headlines, comments, sources -->
<div class="new-left">
<h3>{{item.title}}</h3>
<div>
<p>
<img src=".. /assets/icons/msg.png" alt="Evaluation" />
<span>{{ item.reads }}</span>
<span>{{ item.from }}</span>
</p>
<h4>{{ item.date }}</h4>
</div>
</div>
<! -- Picture on the right side of news -->
<div class="new-right">
<! -- <img :src="imgsList[oneItem.image]" alt="PIC" /> -->
</div>
</router-link>
</div>
</div>
</div>
</template>
<script>
// Introduce the prepared news image related information
import imgsList from ".. /components/newsImgs.js";
import { setTimeout.clearTimeout } from "timers";
export default {
data() {
return {
listData: [].oneItemHeight: 100.//2. Step 2: Border + padding +width for each
containerHeight: 0.maxContainerSize: 0.// The maximum number of data items that can be displayed on the screen
startIndex: 0
// endIndex: 0
};
},
created() {
this.getListData(20);
},
mounted() {
this.getContainSize();
},
computed: {
endIndex() {
let endIndex = this.startIndex + this.maxContainerSize; //9 Step 9: Note that the bottom of the container may be empty, so we need to make a judgment
if (endIndex > this.listData.length) {
// Consider special cases: the last screen of data does not cover the entire screen
endIndex = this.listData.length - 1; // At this point, the scroll has reached the bottom
}
console.log(endIndex, "========endIndex=========");
console.log(this.maxContainerSize, "========maxContainerSize=========");
return endIndex;
},
//10 Step 10: Define an arraylist element to display from the retrieved array
showDataList() {
return this.listData.slice(this.startIndex,this.endIndex)
},
},
watch: {},methods: {
getListData(num) {
return this.$axios
.get("http://localhost:4000/data? num=" + num)
.then(res= > {
this.listData = res.data.list;
})
.catch(() = > {
this.msg = "Request failed please try again later...";
return false;
});
},
getContainSize() {
// step 1: Calculate the height of the container
let height = this.$refs.scrollContainer.offsetHeight;
//3. Step 3: Height of the whole outer box/height of each = maximum number of bars that can be loaded on each screen
let num = height / this.oneItemHeight;
//4. Step 4: Note: if a little bit is shown above and a little bit is shown below then the current amount is the integer +2
let maxNum = Math.floor(num) + 2;
this.maxContainerSize = maxNum;
console.log(this.maxContainerSize);
},
// Calculate the data to roll out
setStartIndex() {
let scrollTop = this.$refs.scrollContainer.scrollTop; // Current roll out height
let currentIndex = Math.floor(
this.$refs.scrollContainer.scrollTop / this.oneItemHeight // The number of pieces of data to roll out
);
if (currentIndex == this.startIndex) {
return;
}
this.startIndex = currentIndex;
console.log(this.startIndex, "===startIndex====");
},
// Count startIndex while listening to the scroll method
handleScroll() {
this.setStartIndex(); }}};</script>
<style lang="scss" scoped>
.news-box {
width: 100%;
max-width: 800px;
height: 100%;
.scroll-container {
width: 100%;
height: 100%;
overflow-y: auto;
.one-new {
text-decoration: none;
display: block;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
border-bottom: 1px solid #ddd;
padding: 14px 10px 5px;
.new-left {
height: 80px;
position: relative;
h3 {
padding: 0;
margin: 0;
font-size: 16px;
text-align: justify;
color: # 555;
}
div {
position: absolute;
width: 100%;
bottom: 10px;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
align-items: center;
p {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
align-items: center;
img {
height: 16px;
}
span {
font-size: 12px;
color: # 555;
margin-left: 3px;
margin-right: 3px; }}h4 {
font-size: 12px;
color: # 888; }}}.new-right {
margin-left: 10px;
img {
height: 68px; }}}.msg h2 {
font-size: 18px;
text-align: center;
color: # 666;
padding-top: 58px; }}}</style>
Copy the code
Attach -3 drop – down scroll to append display data
<template>
<div class="news-box">
<! Step 7: Listen for scroll events -->
<div class="scroll-container" ref="scrollContainer" @scroll.passive="handleScroll">
<! Step 13: We need to add a box because our top and bottom contents are temporarily supported by the padding -->
<div :style="{ paddingTop:topBlankFill+'px', paddingBotom:bottomBlankFill+'px' }">
<div v-for="(item, index) in showDataList" :key="index">
<router-link class="one-new" :to=" '/article/' + item.title + '/'+ item.reads + '/'+ item.from + '/'+ item.date + '/'+ item.image ">
<! -- Headlines, comments, sources -->
<div class="new-left">
<h3>{{item.title}}</h3>
<div>
<p>
<img src=".. /assets/icons/msg.png" alt="Evaluation" />
<span>{{ item.reads }}</span>
<span>{{ item.from }}</span>
</p>
<h4>{{ item.date }}</h4>
</div>
</div>
<! -- Picture on the right side of news -->
<div class="new-right">
<! -- <img :src="imgsList[oneItem.image]" alt="PIC" /> -->
</div>
</router-link>
</div>
</div>
</div>
</div>
</template>
<script>
// Introduce the prepared news image related information
import imgsList from ".. /components/newsImgs.js";
import { setTimeout.clearTimeout } from "timers";
export default {
data() {
return {
listData: [].oneItemHeight: 100.//2. Step 2: Border + padding +width for each
containerHeight: 0.maxContainerSize: 0.// The maximum number of data items that can be displayed on the screen
startIndex: 0
// topBlankFill: 50,
// bottomBlankFill: 20
// // endIndex: 0,
};
},
created() {},
async mounted() {
this.getContainSize();
this.listData = await this.getListData(20);
console.log(this.$refs.scrollContainer.scrollTop);
},
computed: {
endIndex() {
let endIndex = this.startIndex + this.maxContainerSize; //9 Step 9: Note that the bottom of the container may be empty, so we need to make a judgment
if (endIndex > this.listData.length) {
// Consider special cases: the last screen of data does not cover the entire screen
endIndex = this.listData.length - 1; // At this point, the scroll has reached the bottom
}
console.log(endIndex, "========endIndex=========");
console.log(this.maxContainerSize, "========maxContainerSize=========");
return endIndex;
},
//10 Step 10: Define an arraylist element to display from the retrieved array
showDataList() {
return this.listData.slice(this.startIndex, this.endIndex);
},
//11 Step 11: You need to define a height for the upper blank
topBlankFill() {
return this.startIndex * this.oneItemHeight;
},
//12 Step 12: You need to define the height of the whitespace
bottomBlankFill() {
return (this.listData.length - this.endIndex) * this.oneItemHeight; }},watch: {},
methods: {
getListData(num) {
return this.$axios
.get("http://localhost:4000/data? num=" + num)
.then(res= > {
return res.data.list;
})
.catch(() = > {
this.msg = "Request failed please try again later...";
return false;
});
},
getContainSize() {
// step 1: Calculate the height of the container
let height = this.$refs.scrollContainer.offsetHeight;
//3. Step 3: Height of the whole outer box/height of each = maximum number of bars that can be loaded on each screen
let num = height / this.oneItemHeight;
//4. Step 4: Note: if a little bit is shown above and a little bit is shown below then the current amount is the integer +2
let maxNum = Math.floor(num) + 2;
this.maxContainerSize = maxNum;
console.log(this.maxContainerSize);
},
// Calculate the data to roll out
setStartIndex() {
let scrollTop = this.$refs.scrollContainer.scrollTop; // Current roll out height
console.log(this.$refs.scrollContainer.scrollTop, "scrollTop");
let currentIndex = Math.floor(
this.$refs.scrollContainer.scrollTop / this.oneItemHeight // The number of pieces of data to roll out
);
if (currentIndex == this.startIndex) {
return;
}
this.startIndex = currentIndex;
console.log(this.startIndex, "===startIndex====");
},
// Count startIndex while listening to the scroll method
async handleScroll() {
this.setStartIndex();
StartIndex + contentSize > data.length-1
console.log(
this.startIndex,
this.maxContainerSize,
this.showDataList.length
);
if (
this.startIndex + this.maxContainerSize >=
this.listData.length - 1
) {
console.log("Rolled to the bottom.");
// Append data
let request = await this.getListData(20);
this.listData = [...request, ...this.listData];
console.log(this.listData); }}}};</script>
<style lang="scss" scoped>
.news-box {
width: 100%;
max-width: 800px;
height: 100%;
.scroll-container {
width: 100%;
height: 100%;
overflow-y: auto;
.one-new {
text-decoration: none;
display: block;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
border-bottom: 1px solid #ddd;
padding: 14px 10px 5px;
.new-left {
height: 80px;
position: relative;
h3 {
padding: 0;
margin: 0;
font-size: 16px;
text-align: justify;
color: # 555;
}
div {
position: absolute;
width: 100%;
bottom: 10px;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
align-items: center;
p {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
align-items: center;
img {
height: 16px;
}
span {
font-size: 12px;
color: # 555;
margin-left: 3px;
margin-right: 3px; }}h4 {
font-size: 12px;
color: # 888; }}}.new-right {
margin-left: 10px;
img {
height: 68px; }}}.msg h2 {
font-size: 18px;
text-align: center;
color: # 666;
padding-top: 58px; }}}</style>
Copy the code
Attached – 4
<template>
<div class="news-box">
<! Step 7: Listen for scroll events -->
<div class="scroll-container" ref="scrollContainer" @scroll.passive="handleScroll">
<! Step 13: We need to add a box because our top and bottom contents are temporarily supported by the padding -->
<div :style="{ paddingTop:topBlankFill+'px', paddingBotom:bottomBlankFill+'px' }">
<div v-for="(item, index) in showDataList" :key="index">
<router-link class="one-new" :to=" '/article/' + item.title + '/'+ item.reads + '/'+ item.from + '/'+ item.date + '/'+ item.image ">
<! -- Headlines, comments, sources -->
<div class="new-left">
<h3>{{item.title}}</h3>
<div>
<p>
<img src=".. /assets/icons/msg.png" alt="Evaluation" />
<span>{{ item.reads }}</span>
<span>{{ item.from }}</span>
</p>
<h4>{{ item.date }}</h4>
</div>
</div>
<! -- Picture on the right side of news -->
<div class="new-right">
<! -- <img :src="imgsList[oneItem.image]" alt="PIC" /> -->
</div>
</router-link>
</div>
</div>
</div>
</div>
</template>
<script>
// Introduce the prepared news image related information
import imgsList from ".. /components/newsImgs.js";
import { setTimeout.clearTimeout } from "timers";
export default {
data() {
return {
listData: [].oneItemHeight: 100.//2. Step 2: Border + padding +width for each
containerHeight: 0.maxContainerSize: 0.// The maximum number of data items that can be displayed on the screen
startIndex: 0.isScrollStatus: null.isRequestStatus: true
// topBlankFill: 50,
// bottomBlankFill: 20
// // endIndex: 0,
};
},
created() {},
async mounted() {
this.getContainSize();
this.listData = await this.getListData(20);
if(!!!!!this.listData && this.listData.length > 0) {
this.listData = [...this.listData];
this.isRequestStatus = false; }},computed: {
endIndex() {
let endIndex = this.startIndex + this.maxContainerSize * 2; //9 Step 9: Note that the bottom of the container may be empty, so we need to make a judgment
if (endIndex > this.listData.length) {
// Consider special cases: the last screen of data does not cover the entire screen
endIndex = this.listData.length - 1; // At this point, the scroll has reached the bottom
}
return endIndex;
},
//10 Step 10: Define an arraylist element to display from the retrieved array
showDataList() {
let startIndex = 0;
let endIndex = 0;
if (this.startIndex <= this.maxContainerSize) {
// It has not been rolled out yet
startIndex = 0;
} else {
startIndex = this.startIndex - this.maxContainerSize * 2; // Need to subtract roll two screen data
}
return this.listData.slice(startIndex, this.endIndex);
},
//11 Step 11: You need to define a height for the upper blank
topBlankFill() {
//20. Step 20: The upper and lower padding is also required
// Step 19: Set the front and rear buffers
let paddingTop = 0;
if (this.startIndex > this.maxContainerSize) {
// Have already rolled out a screen
// Fill the space only when the current scroll position is larger than the screen capacity
paddingTop =
(this.startIndex - this.maxContainerSize) * this.oneItemHeight;
console.log(this.startIndex, this.maxContainerSize,paddingTop);
}
return paddingTop;
},
//12 Step 12: You need to define the height of the whitespace
bottomBlankFill() {
return (this.listData.length - this.endIndex) * this.oneItemHeight; }},watch: {},
methods: {
getListData(num) {
return this.$axios
.get("http://localhost:4000/data? num=" + num)
.then(res= > {
return res.data.list;
})
.catch(() = > {
this.msg = "Request failed please try again later...";
return false;
});
},
getContainSize() {
// step 1: Calculate the height of the container
let height = this.$refs.scrollContainer.offsetHeight;
//3. Step 3: Height of the whole outer box/height of each = maximum number of bars that can be loaded on each screen
let num = height / this.oneItemHeight;
//4. Step 4: Note: if a little bit is shown above and a little bit is shown below then the current amount is the integer +2
let maxNum = Math.floor(num) + 2;
this.maxContainerSize = maxNum;
},
// Calculate the data to roll out
setStartIndex() {
let scrollTop = this.$refs.scrollContainer.scrollTop; // Current roll out height
let currentIndex = Math.floor(
this.$refs.scrollContainer.scrollTop / this.oneItemHeight // The number of pieces of data to roll out
);
if (currentIndex == this.startIndex) {
return;
}
this.startIndex = currentIndex;
},
// Count startIndex while listening to the scroll method
handleScroll() {
// this.debounce(this.scrollFun, 500);
this.requestF();
// this.scrollFun();
},
requestF() {
let requestAnimationFrame =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
// Browser anti-vibration optimization: according to the browser FPS using recursive method, queue call requestAnimationFrame method to achieve optimization
let fps = 30;
let interval = 1000 / fps;
let then = Date.now();
requestAnimationFrame(() = > {
let now = Date.now();
let delta = now - then;
then = now;
this.scrollFun();
if (delta >= interval) {
requestAnimationFrame(arguments.callee); }}); },debounce(fn, delay) {
clearTimeout(this.isScrollStatus);
this.isScrollStatus = setTimeout(function() {
fn();
}, delay);
},
async scrollFun() {
console.log("Rolling.");
this.setStartIndex();
if (this.startIndex + this.maxContainerSize >= this.listData.length - 1) {
// Append data
let request = await this.getListData(20);
this.listData = [...request, ...this.listData]; }}}};</script>
<style lang="scss" scoped>
.news-box {
width: 100%;
max-width: 800px;
height: 100%;
.scroll-container {
width: 100%;
height: 100%;
overflow-y: auto;
.one-new {
text-decoration: none;
display: block;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
border-bottom: 1px solid #ddd;
padding: 14px 10px 5px;
.new-left {
height: 80px;
position: relative;
h3 {
padding: 0;
margin: 0;
font-size: 16px;
text-align: justify;
color: # 555;
}
div {
position: absolute;
width: 100%;
bottom: 10px;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
align-items: center;
p {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
align-items: center;
img {
height: 16px;
}
span {
font-size: 12px;
color: # 555;
margin-left: 3px;
margin-right: 3px; }}h4 {
font-size: 12px;
color: # 888; }}}.new-right {
margin-left: 10px;
img {
height: 68px; }}}.msg h2 {
font-size: 18px;
text-align: center;
color: # 666;
padding-top: 58px; }}}</style>
Copy the code