Before the introduction
Hello, everyone. I am D student from tui Front End Team. Today I will briefly share with you the related content of the virtual long list. rendering
1. Design idea
Virtual list is a technology of on-demand display. In a scene with many similar items, only a few elements in and around the visual area are rendered, and then Dom elements are reused according to the user’s scrolling, which is a means of performance optimization.
The main design ideas are as follows:
- Utilize reuse of Dom elements outside of the viewable area
- Add Padding to the container
- Make the area outside of the viewable area just a padding blank, and only need to render the viewable area and the upper and lower content areas (to avoid too much data and lag rendering of the corresponding data).
Simple Dom structure
<div class="container">
<ul>
<li>2020</li>
<li>2019</li>
<li>2018</li>
<li>2017</li>
<li>2016</li>
<li>2015</li>
<li>2014</li>
</ul>
</div>
Copy the code
Next, before using JavaScript to control behavior, you need to first think about criticality, and the general behavior behind it.
As shown in figure
- Drop down to the threshold, append the first element to the container, then add poddingTop to the container, and the threshold changes.
- After the pull-up to set the threshold, insert the last element before the first element to reduce the container paddingTop, threshold change.
In this example, the initial threshold of the pull-down is the height of the three lI’s, and the initial threshold of the pull-up is 0.
Meanwhile, the padding value at the top of the container is calculated dynamically by changing li, so we need to save a variable to calculate the paddingTop of the container.
2. Main code implementation
let ul = document.getElementsByTagName('ul') [0];
let item = document.getElementsByTagName('li') [0];
// The height of a single item
const ItemWidth = parseInt(getComputedStyle(item).height)
let obj = {
initx: 0.// Controls whether mousemove moves
isMove: false.// The initial maximum value is used to determine the limit of the pull-up
max: 0.// Initial minimum value, used to determine the limit of the pull-down
min: -3 * ItemWidth,
topIndex: 0
}
// Unscrupulously get the Y offset of the element
function getTransY(el) {
if(! el.style.transform) {return 0
}
let str = el.style.transform.replace(/. *? , /.' ')
return parseInt(str)
}
Copy the code
After that, step by step on the container for the mouse event monitoring, to achieve the drag effect.
ul.addEventListener('mousedown'.(e) = > {
// Record the mouse coordinates here to calculate the offset
// Record the initial offset of ul to add the offset to calculate the total offset
obj.isMove = true,
obj.initY = e.clientY
obj.initTrans = getTransY(ul)
})
ul.addEventListener('mousemove'.(e) = > {
if(obj.isMove){
// Original offset + mouse sliding distance
let abs = obj.initTrans + (e.clientY - obj.initY)
// The value cannot be smaller than 0
abs = abs > 0 ? 0 : abs
ul.style.transform = `translate3d(0,${abs}px,0)`
if (abs < obj.min) {
obj.max -= ItemWidth
obj.min -= ItemWidth
// changeStatus(0)
console.log('append')}else if (abs > obj.max) {
obj.max += ItemWidth
obj.min += ItemWidth
// changeStatus(1)
console.log('insertBefore')
}
}
})
ul.addEventListener('mouseup'.() = > {
obj.isMove = false
})
Copy the code
Let’s put down the append and insert code and test the logic.
- additional
- insert
As you can clearly see, the logic makes sense, and the next thing to do is to operate on the elements in ul.
We extract this complicated logic and pass parameters to achieve both append and insert.
function changeStatus(flag) {
let lgh = ul.childElementCount
// Get the first element
let fir = ul.children[0]
// Get the last element
let las = ul.children[lgh - 1]
if (flag) {
// insertBefore
// How does the content change
las.innerText = +fir.innerText + 1
// The index used to calculate paddingTop is subtracted by one
obj.topIndex--
// Ul's paddingTop placeholder value is subtracted by the height of an item for each element inserted
ul.style.paddingTop = obj.topIndex * ItemWidth + 'px'
ul.insertBefore(las, fir)
} else {
// append
// Ul's paddingTop placeholder adds the height of one item each time the first element is appended to the last position
obj.topIndex++
ul.style.paddingTop = obj.topIndex * ItemWidth + 'px'
fir.innerText = +las.innerText - 1
ul.appendChild(fir)
}
}
Copy the code
When this is done, add overflow: Hidden to the ul container and you can easily simulate the visual effect of a virtual infinite list.
Based on this idea, we can simply implement a virtual long list date selector.
conclusion
This article is just a simple introduction to some virtual long list of simple implementation, is really to complete a more complete virtual long list, there are many details need to explore the implementation. But the key is to reuse the Dom to populate new data.
For example, expose custom configuration items and implement vertical or horizontal scrolling.
Or in the non-infinite scrolling scene, given a dummy scroll bar, used to simulate the real scroll bar effect, and can let the user roughly understand the length of the content.
Contributions from “Virtual Long List”