当前位置: 首页 > news >正文

兖州建设局网站网站改进建议有哪些

兖州建设局网站,网站改进建议有哪些,被攻击网站,wordpress 数据库乱码用原生JS实现虚拟列表 介绍 最近在开发需求的时候,有用到 Antd 的虚拟列表组件 rc-virtual-list ,粗略地看了一下源码,于是萌生了自己写一个虚拟列表的想法。当一个列表需要渲染大量数据的时候是非常耗时的,而且在列表滚动的过程…

用原生JS实现虚拟列表

介绍

  • 最近在开发需求的时候,有用到 Antd 的虚拟列表组件 rc-virtual-list ,粗略地看了一下源码,于是萌生了自己写一个虚拟列表的想法。
  • 当一个列表需要渲染大量数据的时候是非常耗时的,而且在列表滚动的过程中会出现卡顿的现象。即使用上懒加载解决了列表初始化时渲染过慢的问题,但是每次拉取下一页数据的时候都会造成列表的重新渲染。随着拉取的数据越来越多,列表渲染时间长、卡顿的问题依然存在。
  • 这个时候虚拟列表就派上用场了。虚拟列表的实现原理简单来说,就是列表并不会把所有的数据都渲染出来,而是通过监听滚动事件然后实时计算当前是哪几条数据显示在页面上,然后只渲染用户可以看见的这几条数据。
  • 在网上找了张图可以说明的更生动些:
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vbz6hBM5-1684195418798)(C:\Users\quyanliang\AppData\Roaming\Typora\typora-user-images\1684195219996.png)]

定高虚拟列表

  • 实现虚拟列表需要两层的div:

  • <style>.list-container {overflow: auto;border: 1px solid black;height: 500px;}
    </style><body><!-- 外部容器用来固定列表容器的高度,同时生成滚动条 --><div class="list-container"><!-- 内部容器用来装元素,高度是所有元素高度的和 --><div class="list-container-inner"></div></div>Ï
    </body>
    
  • 外层的div用来固定高度,也就是图上展示的B区域。内层的div用来装列表元素,也就是图上展示的A区域。给外层的div设置 overflow: auto ,这样当列表元素数量超过B区域的高度时就会出现滚动条。

  • 接下来,我们需要监听外层div的滚动事件,实时计算出显示在可视区域上的第一个元素的坐标 startIndex 和 最后一个元素的坐标 endIndex。假设列表每个元素的高度都是60px,那么 startIndex 就等于外层 div 顶部卷起来的长度除以列表元素的高度,而 endIndex 就等于 startIndex + 可视区域能展示的元素个数 :

  • const itemHeight = 60
    const height = 500
    const startIndex = Math.floor(outerContainer.scrollTop / itemHeight)
    const endIndex = startIndex + Math.ceil(height / itemHeight)
    
  • 然后用 startIndex 和 endIndex 去截取数据,并渲染在内层 div 上:

  • const viewData = data.slice(startIndex, endIndex + 1)
    const innerContainer = document.querySelector('.list-container-inner')
    innerContainer.innerHTML = ''
    for(let i = 0; i < viewData.length; i++) {const item = document.createElement('div')item.innerHTML = viewData[i]innerContainer.appendChild(item)
    }
    
  • 最后一步,虽然我们只需要渲染在可视区域上的元素,但是我们还需要给内层的 div 设置 padding-top 和 padding-bottom ,替代那些不需要渲染的元素。由此保证虚拟列表是可以滚动的,而且滚动条位置和列表元素位置是相对应的。 padding-top 等于 startIndex 之前的元素高度和, padding-bottom 等于 endIndex 之后的元素高度和:

  • const paddingTop = startIndex * itemHeight
    const paddingBottom = (data.length - endIndex) * itemHeight
    innerContainer.setAttribute('style', `padding-top: ${paddingTop}px; padding-bottom: ${paddingBottom}px`)
    
  • 完整代码:

  • <style>.list-container {overflow: auto;border: 1px solid black;height: 500px;}
    </style><body><!-- 外部容器用来固定列表容器的高度,同时生成滚动条 --><div class="list-container"><!-- 内部容器用来装元素,高度是所有元素高度的和 --><div class="list-container-inner"></div></div><script>/** --------- 一些基本变量 -------- */const itemHeight = 60const height = 500/** --------- 生成数据 -------- */const initData = () => {const data = []for(let i = 0; i < 15; i++) {data.push({content: `内容:${i}`, height: itemHeight, color: i % 2 ? 'red' : 'yellow'})}return data}const data = initData()const contentHeight = itemHeight * data.lengthconst outerContainer = document.querySelector('.list-container')const scrollCallback = () => {// 获取当前要渲染的元素的坐标const scrollTop = Math.max(outerContainer.scrollTop, 0)const startIndex = Math.floor(scrollTop / itemHeight)const endIndex = startIndex + Math.ceil(height / itemHeight)const innerContainer = document.querySelector('.list-container-inner')// 从data取出要渲染的元素并渲染到容器中const viewData = data.slice(startIndex, endIndex + 1)innerContainer.innerHTML = ''for(let i = 0; i < viewData.length; i++) {const item = document.createElement('div')const itemData = viewData[i]item.innerHTML = itemData.contentitem.setAttribute('style', `height: ${itemData.height}px; background: ${itemData.color}`)innerContainer.appendChild(item)}// 未渲染的元素由padding-top和padding-bottom代替,保证滚动条位置正确const paddingTop = startIndex * itemHeightconst paddingBottom = (data.length - endIndex) * itemHeightinnerContainer.setAttribute('style', `padding-top: ${paddingTop}px; padding-bottom: ${paddingBottom}px`)}// 首屏渲染scrollCallback()// 监听外部容器的滚动事件outerContainer.addEventListener('scroll', scrollCallback)</script>
    </body>
    

不定高虚拟列表

  • 上面实现的是元素高度固定的虚拟列表,对于元素高度不固定的情况,虚拟列表实现起来会更复杂一些。

  • 因为我们事先不知道元素的高度,所以在监听滚动事件的过程中,需要遍历一遍列表获取每个元素的高度,由此算出 startIndex 、 endIndex 等数据。不过在第一次渲染之前,因为元素没有渲染出来,我们拿不到元素的真实高度。所以这时候需要给元素一个最小高度 itemHeight ,通过 itemHeight 来计算 startIndex 和 endIndex,由此保证第一次渲染出来的元素能占满整个可视区域。

  • 另外,当元素渲染出来以后,我们用一个字典去记录每个元素的真实高度,供下次滚动事件触发时 startIndex 和 endIndex 的计算。

  • startIndex 的算法是在遍历列表元素的过程中,逐步累加当前元素的高度得到 contentHeight ,当第一次出现 contentHeight 大于容器顶部卷起来的长度的时候,说明当前元素是列表可视区域的第一个元素,记为 startIndex。

  • endIndex 的算法是当第一次出现 contentHeight 大于 容器顶部卷起来的长度 + 容器高度 的时候,说明当前元素是列表可视区域的最后一个元素,记为 endIndex 。

  • 完整代码:

  • <style>.list-container {overflow: auto;border: 1px solid black;height: 500px;}
    </style><body><!-- 外部容器用来固定列表容器的高度,同时生成滚动条 --><div class="list-container"><!-- 内部容器用来装元素,高度是所有元素高度的和 --><div class="list-container-inner"></div></div><script>/** --------- 一些基本变量 -------- */const itemHeight = 60const height = 500/** --------- 生成数据 -------- */const getRandomHeight = () => {// 返回 [60, 150] 之间的随机数return Math.floor(Math.random() * (150 - itemHeight + 1) + itemHeight)}const initData = () => {const data = []for(let i = 0; i < 15; i++) {data.push({content: `内容:${i}`, height: getRandomHeight(), color: i % 2 ? 'red' : 'yellow'})}return data}const data = initData()const cacheHeightMap = {}const outerContainer = document.querySelector('.list-container')const scrollCallback = () => {let contentHeight = 0let paddingTop = 0let upperHeight = 0let startIndexlet endIndexconst innerContainer = document.querySelector('.list-container-inner')const scrollTop = Math.max(outerContainer.scrollTop, 0)// 遍历所有的元素,获取当前元素的高度、列表总高度、startIndex、endIndexfor(let i = 0; i < data.length; i++) {// 初始化的时候因为元素还没有渲染,无法获取元素的高度// 所以用元素的最小高度itemHeight来进行计算,保证渲染的元素个数能占满列表const cacheHeight = cacheHeightMap[i]const usedHeight = cacheHeight === undefined ? itemHeight : cacheHeightcontentHeight += usedHeightif (contentHeight >= scrollTop && startIndex === undefined) {startIndex = ipaddingTop = contentHeight - usedHeight}if (contentHeight > scrollTop + height && endIndex === undefined) {endIndex = iupperHeight = contentHeight}}// 应对列表所有元素没有占满整个容器的情况if (endIndex === undefined) {endIndex = data.length - 1upperHeight = contentHeight}// 未渲染的元素的高度由padding-top和padding-bottom代替,保证滚动条位置正确// 这里如果把设置pading的操作放在渲染元素之后,部分浏览器滚动到最后一个元素时会有问题const paddingBottom = contentHeight - upperHeightinnerContainer.setAttribute('style', `padding-top: ${paddingTop}px; padding-bottom: ${paddingBottom}px`)// 从data取出要渲染的元素并渲染到容器中const viewData = data.slice(startIndex, endIndex + 1)innerContainer.innerHTML = ''const fragment = document.createDocumentFragment()for(let i = 0; i < viewData.length; i++) {const item = document.createElement('div')const itemData = viewData[i]item.innerHTML = itemData.contentitem.setAttribute('style', `height: ${itemData.height}px; background: ${itemData.color}`)fragment.appendChild(item)}innerContainer.appendChild(fragment)// 存储已经渲染出来的元素的高度,供后面使用const children = innerContainer.childrenlet flag = startIndexfor(const child of children) {cacheHeightMap[flag] = child.offsetHeightflag++}}// 首屏渲染scrollCallback()// 监听外部容器的滚动事件outerContainer.addEventListener('scroll', scrollCallback)</script>
    </body>
  • 在这里插入图片描述

http://www.yayakq.cn/news/34534/

相关文章:

  • 网站怎么做免费推广方案美容整形网站建设
  • 找外包公司做网站网络营销能干什么工作
  • 济宁市工程建设职业学校网站四川网站建设平台
  • 跑腿公司怎么做网站关于网站建设的工作总结
  • 文山网站建设福州公关公司
  • 传奇网页版在线玩网页关键词优化软件
  • 桂林网站定制网站域名迁移公告
  • 做网站用什么好广州加盟网站建设
  • 百度网站回档怎么能恢复app下载网址进入下载
  • 如何自建网站卖产品江苏亿之盛建设有限公司网站
  • 做抽奖网站合法吗php网站的数据库在哪
  • 韩文网站域名备案WordPress配置七牛代码
  • 网站开发摊销年限网站内容页面怎么做外链
  • 扬州网站优化美词网站建设
  • 南充市住房和城乡建设局考试网站wordpress自动加载链接
  • 怎么做网站广告古董设计师找图网站
  • 做网站 看什么书绵阳网站排名
  • 百丽优购物官方网站营销网站
  • 商城网站营销系统源码深圳东门密室逃脱
  • 贵州旅游网站建设策划书珠宝品牌网站设计
  • 辽宁鹤城建设集团网站做食品的采购员常用网站
  • 黑龙江建设厅网站 孙宇wordpress更换服务器搬家教程
  • 官网建站模板库久久建筑网安全吗
  • 河北住房和城乡建设局网站首页手表网站
  • 企业网站ppt怎么做网站统计cnzz
  • 品牌型网站建设解决方案wordpress类似网站
  • 信誉好的购物网站建设郑州网站建设包括哪些
  • 产品经理做网站浙江网站建设正规公司
  • 雇人做淘宝网站多少钱提升关键词优化排名软件
  • 最简单网站建设湛江市建设局官方网站