vue长列表性能优化 当item的高度不确定时

<template>

   <div class="home">

     <div class="warp" ref="warp" @scroll="jko()">

       <!-- 为了显示滚动条 -->

        <div ref="scrollHeight"></div>

        <div class="fry" :style="{transform: `translateY(${mko}px)`}">

          <div v-for="(item,index) in visibleData" :key="index">{{item}}</div>

       </div>

     </div>

  </div>

</template>

<script>

export default {

  name: 'HelloWorld',

  props: {

     

  },

  data(){

    return{

       shim:Array(100).fill("kkkkkkk"),

       size:20,//已知的元素的高度或者预估高度

       hjk:'',

       lop:8,//这个是我们希望显示的元素条数

       start:0,//这个是选取的slice的第一个值,初始为0

       mko:0,//这个是让可显示的区域一直跟随着滚动而变化的值

       end:this.lop,//这个是选取slice的第二个值,也就要显示元素的最大范围

       variable: true, // 每一项是否高度固定,这是第二种情况

       positionListArr:[],

       prevCount:0

    }

  },

  mounted(){

     this.$refs.warp.style.height=this.lop*this.size+'px'

     //这里是为了扩充内容区域,怕不显示 ,算是一种优化

     this.$refs.scrollHeight.style.height=this.shim.length*this.size+'px'

     //缓存每一项元素的高度

     this.mkomlp()

  },

  computed:{

      visibleData() {

         /*// 下面有用到 Math.min 是防止前面或后面没有 this.keeps 项,也就是刚开始或快到底的情况

         const prevCount = Math.min(this.start, this.lop) // 展示的项数之前多渲染几项

         this.prevCount = prevCount // handleScroll 方法里要用

         const renderStart = this.start -  prevCount // 真正的渲染开始项

         const nextCount = Math.min(this.shim.length - this.end, this.lop) // 展示的项数之后多渲染几项

         const renderEnd = this.end +  nextCount // 真正的渲染结束项的后一项,因为 slice 是不包括 end 参数的*/


 

         return this.shim.slice(this.start,this.end)

    }

  },

  methods:{

    jko(){

       const ko=this.$refs.warp.scrollTop

       if(this.variable){//这是不确定高度的情况

        //首先再高度不确定的时候,思路是一样的,要先查找到动态的start

        this.start=this.getStartIndex(ko) // 获取开始展示的那一项的下标

         console.log(this.start)

        this.end = this.start + this.lop

         console.log(this.end)

        // 下面这句用三元运算符是因为 this.positionListArr[this.start - this.prevCount] 的值可能为 undefined,

        // 比如当从下往回滚动的时候 this.prevCount 的值有可能会有等于前一次滚动时的 this.start 的值的时候,大于现在 this.start 的值

        this.mko = this.positionListArr[this.start+1].top

        console.log(this.mko)

       }else{//这是高度确定的情况

          this.start=Math.ceil(ko/this.size)-1 >=0 ? Math.ceil(ko/this.size)-1:0

            this.end=this.start+this.lop

            this.mko=this.start * this.size

       }

       

    },

   

    getStartIndex(scrollTop) {

      //这里的二分法其实是说,在每次滚动的时候都找到我们与scrollTop相近的值,然后返回这个值

      //然后让temp保存最相近的那一项

        用二分法查找滚动距离是 positionListArr 哪一项的 bottom 的值

       

         var startm=0//这个代表positionListArr的数据的第一项

         var endb=this.positionListArr.length-1//代表最后一项的坐标

        // 用 temp 存储得不到精确值时最终返回的值,因为可能滚动的距离的值不会等于 positionListArr 数组里

        // 任何一项的 bottom 的值,所以只好存储一个最接近的值

        var temp=null

        while(startm <= endb){

        let kop=parseInt(startm+(endb-startm)/2)//这一步是得到中间那一项的index值

        var nmlo=this.positionListArr[kop].bottom//这一步是得到中间的那一项的bottom的距离顶部的值

        //这一步是我们当在上面隐藏的区域等于我们当前中间项的bottom的值时

          if(scrollTop==nmlo){

            // 滚动的值刚好等于中间那一项的 bottom 值,则此时的展示起点 start 应该为中间那一项的下一项

            return kop+1

          }else if(scrollTop<nmlo){//这里时让他往上找还是往下找

             // 滚动的值小于中间那一项的 bottom 值:

                endb=kop-1

             if (temp === null || temp > kop ) // temp >kop 保证了目标值所在范围越变越小

                temp = kop

          }else if(scrollTop > nmlo){

            // 滚动的值大于中间那一项的 bottom 值:

               startm=kop+1// 让 start 移动到中间的那一项的后面一项

            if (temp === null || temp > kop ) // temp >kop 保证了目标值所在范围越变越小

                temp = kop

          }

        }

        return temp


 

    },

    //缓存this.shim的每一项的高度,top和bootom

    // 注意: () => ({}) 为返回对象的写法

    mkomlp(){

       this.positionListArr=this.shim.map((item,index)=>({

          height: this.size,

          top: index * this.size,

          bottom: (index + 1) * this.size

       }))

    }

   

  }

}

</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->

<style scoped>

.warp{

  width: 500px;

  overflow: scroll;

  position: relative;

}

.fry{

  width: 100%;

  position: absolute;

  top: 0px;

  left: 0;

}

</style>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值