懒加载之几百张图片
网页要展示很多张图片 手机性能不够,渲染过多图片容易造成页面卡死 甚至页面奔溃。。。
最近做项目的时候就遇到了这样的问题。
后端将所有URL链接都返回过来,如果直接循环渲染到img标签里面,大于几十张有些安卓机子就会死机
所以必须考虑用到懒加载,即 先不渲染所有URL链接,滚动到可视区域范围,再去渲染后面的URL,这样操作即使几百张图片在苹果机子也是没问题的
我这里用的是react hooks的解法,其他可模仿思路。
(一)
默认先加载几页,保证会有滚动条的情况,
然后向下滚动,滚动到滚动条到底可加载下一页
包裹图片的外框我称为 box
box的全部总高(scrollHeight) - box可见区域高(clientHeight) <= box滚动条的高度(scrollTop)
(因为我的项目中图片大小是A4纸大小,所以默认显示的页数是2页,2页就可以有滚动条了,可以按照实际情况来定义默认页数)
const [pageIdx, setPageIdx] = useState(0) // 当前页数 useEffect(() => { setPageIdx(2) }, []) const handleScroll = () => { // 滚动事件:滚动加载 if (pageIdx < contentImgs.length - 1 && (myref.current.scrollHeight - myref.current.clientHeight) <= myref.current.scrollTop) { setPageIdx(pageIdx + 1) } } // contentImgs 所有的图片链接 const renderContent = () => { // 正文部分 return contentImgs.slice(0, pageIdx+1).map(f => <img src={f} key={f} />) }
这个方法比较简单了,但是毕竟随着往下滚动 渲染的越来越多 终究支撑不住
那么就得考虑永远只渲染10页的情况
(二)
只渲染10页,需要 不仅要考虑到上拉加载,也要考虑下拉加载, 因为每10页都得重新加载
这还得考虑方向,是向上还是向下,上拉的话pageNum要增加 下拉要减少
let endToast = false; // 提示结束 避免反复刷 const myBox = document.getElementById('myInput') const pageH = (1123 + 10) * scale; // 每页的高度 //懒加载处理 const [pageIdx, setPageIdx] = useState(0) // 当前页数 const [imgs, setImgs] = useState() // 当前展示的图片链接 const [startY, setStartY] = useState(0) // 触摸开始位置(用于判断滚动方向) const [endY, setEndY] = useState(0) // 触摸结束位置(用于判断滚动方向) useEffect(() => { if (!myBox) return; if (contentImgs.length > 100) { setPageIdx(10) const imgsList = contentImgs.slice(0, 10) const curImg = [] curImg.push(...imgsList) setImgs(curImg) myBox.ontouchstart = function(e) { const pageY = e.changedTouches[0].pageY setStartY(pageY) } myBox.ontouchend = function(e) { const pageY = e.changedTouches[0].pageY setEndY(pageY) } } else { setPageIdx(3) // 小于100页 默认展示3页 } }, [contentImgs]) useEffect(() => { if (contentImgs.length <= 100) return; // 上拉,下滑 if (endY < startY) { const totalHeight = myBox.clientHeight + myBox.scrollTop if (totalHeight === myBox.scrollHeight && !endToast) { if (pageIdx >= contentImgs.length) { endToast = true; Toast.loading('加载完毕', 2); return } Toast.loading('正在加载...', 2); myBox.scrollTop = 0; setPageIdx(pageIdx + 10) const imgsList = contentImgs.slice(pageIdx, pageIdx + 10) setImgs([...imgsList]) } } // 下拉,上滑 if (endY > startY && myBox.scrollTop === 0 && pageIdx !== 10) { endToast = false; Toast.loading('正在加载...', 2); myBox.scrollTop = pageH * 10; setPageIdx(pageIdx - 10) const imgsList = contentImgs.slice(pageIdx - 20, pageIdx - 10) setImgs([...imgsList]) } }, [startY, endY]) const renderContent = () => { // 正文部分 return imgs.map((f, i) => <img src={f} key={i} />) }
但是方案二 会有弊端 因为是分段展示,下拉的时候 会出现从第20页跳到10页再到19页 即使有loading效果 还是会有个跳动的过程,可以优化下
有小伙伴刷到 如果更好的办法,欢迎留言,希望可以不吝赐教

浙公网安备 33010602011771号