分享下”如何通过n个容器元素实现无限滚动“这篇文章,文中根据实例编码详细介绍,或许对大家的编程之路有着一定的参考空间与使用价值,需要的朋友接下来跟着云南仟龙Mark一起学习一下吧。
场景
如何正确渲染多达10000个元素的列表。
无限下拉加载技术使用户在大量成块的内容面前一直滚动查看。这种方法是在你向下滚动的时候不断加载新内容。
当你使用滚动作为发现数据的主要方法时,它可能使你的用户在网页上停留更长时间并提升用户参与度。随着社交媒体的流行,大量的数据被用户消费。无线滚动提供了一个高效的方法让用户浏览海量信息,而不必等待页面的预加载。
如果我们换一种思维方式,如果一个页面上面有10000个通栏组件构成,我们如何使用5个组件动态去渲染整个页面呢?
解决思路
在对长列表的优化中我们有很多的方案,例如分页,懒加载等等。 有非常好的交互(菊花图),让用户去等待一下。这样的方案也是非常的成功。
如何另辟蹊径?
- 在单页运用中我们是否可以对分页方案做一次分析,每页10个元素,分页每次渲染10个元素根据
- 我们能否用一个支架撑起整个列表的长度 当屏幕滚动到对应的位置就渲染对应的10个元素
闪烁问题
当我们按这个思路实现后会出现闪烁的问题,由于滚动事件比较频繁,我们发现在我们看见的元素在不断的重新绘制,因为我们每次的过场是找到哪十个元素是需要渲染的,然后就直接替换了
这里的思路是我在看的到屏幕位置渲染10个再向上和向下各衍生渲染10个,总共30个,控制渲染的时候总是替换最上面或者最下面的元素,这样处于中间我们可以看见的部分就没有做重新重绘渲染。只是在预渲染的数据在做重绘。
原理
实现一个组件,可以显示具有5个元素的固定窗口大小的n个项目的列表: 即在任何时候,无限滚动n元素上也仅存在5个DOM容器。
<ul>
<li style="transform: translate3d(0px, 0px, 0px);">……</li>
<li style="transform: translate3d(0px, 60px, 0px);">……</li>
</ul>
• 长列表内容一般都有规律,这个列表的高度是可以直接通过
- 的个数直接算出来的,比如1000个元素,每个元素的高是60px,那么我们很快就能算出真个列表的高度是60000px
• 有了容器后将内部的 - 相对于
- 进行绝对定位,在用js直接算出每一个
- 对应的’transform: translate3d(0px, 0px, 0px);'属性
• 通过监听scroll时间不断的去找到当前位置需要渲染的 - 的, 和上一组渲染数据进行对比,有相同的
- 就跳过,找出和上一组渲染数据的不同元素,然后做对应的替换
-
例如: 100 个元素,首页就显示5个,初始化[0,1,2,3,4] 这5个
- 需要渲染,当我向下滚动一点的时候出现 [1,2,3,4,5] 这几个
- 需要渲染,这时候不要直接做整体替换,只应该替换差异项,结构应为[5,1,2,3,4],由于是绝对定位,会脱离标准流,单个的重绘不会影响其他四个,从而提升性能。
如何实现 -
<html lang="en"><head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<title>Document</title>
<style>
body,
ul,
li {
margin: 0;
padding: 0;
list-style: none;
}ul {
position: relative;
}ul li {
position: absolute;
top: 0;
width: 100%;
height: 31px;
line-height: 32px;
border-bottom: 1px solid #ccc;
}
</style>
</head><body>
<ul>
</ul>
</body>
<script>
//总容器
var list = [];
// 可视范围内元素容器
var showList = [];
// 渲染容器
var renderList = [];
// 每个容器的高度
var lineHeight = 32// 初始化1000 个元素
for (var i = 0; i < 1000; i++) {
list.push({ id: i, text: ‘第’ + (i + 1) + ‘个元素’, top: i * lineHeight, bottom: (i + 1) * lineHeight })
}
// 初始化容器高度
$(‘ul’).attr(‘style’, ‘height:’ + 1000 * lineHeight + ‘px’)
// 寻找初始化容器的
function render(top, bottom) {
showList = [http://www.qlyl1688.com/products/sbsdzx.html]
// 标记哪些数据和已经渲染后的是重复的,这部分将不会重复渲染
var sameIndex = []
// 找出滚动位置再哪一个元素上
var currentIndex = 0
for (var i = 0; i < list.length; i++) {
var item = list[i]
if (item.top <= window.scrollY && item.bottom > window.scrollY) {
currentIndex = i;
break;
}
}
var range = 0
// 在当前找到的元素分别向上和向下找需要显示的元素,总共的个数达到35个为止
while (range < 100 && showList.length + sameIndex.length < 35) {
if (currentIndex - range >= 0) {
// 对比满足条件的元素是否在已经渲染列表中,在就做标记,不在就放在showList 当时候替换没有被标记的元素
if (renderList.includes(list[currentIndex - range].id)) {
// sameIndex.push(currentIndex-range)
sameIndex.unshift(renderList.indexOf(list[currentIndex - range].id))
} else {
showList.unshift(list[currentIndex - range])
}
}if (currentIndex + range < list.length && range != 0) {
if (renderList.includes(list[currentIndex + range].id)) {
sameIndex.push(renderList.indexOf(list[currentIndex + range].id))
} else {
showList.push(list[currentIndex + range])
}
}
range++
}
// 将对比出来的新的需要渲染的元素和没有被标记的渲染列表元素做替换
if (renderList.length > 0) {
for (var i = 0; i < renderList.length; i++) {
if (!sameIndex.includes(i) && showList.length) {
renderList[i] = showList.shift().id
KaTeX parse error: Expected 'EOF', got '}' at position 163: …x, 0px);') }̲ } } el…(‘ul’).append(KaTeX parse error: Expected 'EOF', got '#' at position 91: …x, 0px);"">#̲' + list[key].i…(window).scroll(function (e) {
render()
});</script>
</html>
TODO
- 对比替换容器元素的方法总是感觉还能优化,这样就能提升运行效率,从而优化快速滚动出现的白屏
- 这里也出一个思考题[0,1……,10000], 每次从中取出5个元素,新选出来的和旧的进行对比,保留两个数组的交集部分,用新数组里面的新元素替换老数组里面的非交集部分, 例如第一次是[0,1,2,3,4],第二次是[2,3,4,5,6] 那么对比后生成[5,6,2,3,4],第三次如果是[4,5,6,7,8],生成的就为[5,6,7,8,4]。用最少的代码数得到这个结果数组。
总结
-
根据数据信息进行合理布局和复位
-
根据感觉精准定位让容器摆脱规范流
-
根据数据对比,找到差别容器原素,每一次重绘尽量避免的容器原素。
下一期-----组件配搭完成长目录
关键环节
-
组件有别于有周期性的list, 组件的高度有可能不可控性,会按照不一样的智能手机机器设备而发生不用的高度
-
因为组件高度的同,3D渲染地区内几个组件的数目也是不一样的,这就导致了容器数量不一样
-
针对高度不太好根据统计数据同时开展测算的,假如必须 一次总体3D渲染随后根据dom去测算部位和高度是十分消耗第一次载入特性的。
今天的文章就分享到这啦,内容转自脚本之家,下篇文章再见!