如何让vue长列表快速加载

vue-long-list-load,满足特殊条件的长列表加载。支持:1、各个节点高度不同且可自由设定 2、各个节点可修改不影响加载效果 3、可精确的滚动到指定位置。

背景

有个长列表渲染的需求,本来用vue-virtual-scroll-list的。但是每个节点的高度不一样,用着有点问题。如果也有相应的需求可以参考下我的方案。欢迎大家交流!

vue-long-list-load

满足特殊条件的的长列表加载。 列表内各个节点高度不一,各个节点可以进行修改,定位到指定位置指定节点。 www.npmjs.com/package/vue…

主要内容

  1. vue-long-list-load 与 vue-virtual-scroll-list 对比
  2. vue-long-list-load实现思路
  3. 基本代码
  4. 插件使用方式
  5. 插件参数说明

一、组件对比

vue-long-list-load ,vue-virtual-scroll-list两个插件各有优缺点,当我们在选择插件的时候要选择最适合应用场景的插件。下面是两个插件的基本功能对比。vue-long-list-load 主要特点是适用于各个节点尺寸不统一的场景,vue-virtual-scroll-list更适用于高度统一节点以列表长度以w计的这种列表。

组件 vue-long-list-load vue-virtual-scroll-list
npm地址 www.npmjs.com/package/vue… www.npmjs.com/package/vue…
核心 先空dom占位,显示区域内组件挂载显示 计算当前显示区域内要显示的组件挂载
横向 支持 支持
列表内高度一致 支持 支持
列表内高度不一致 支持 支持不好
滚动到指定组件 支持 高度不一致时计算不准确
滚动事件 支持 支持
组件高度改变事件 支持 支持
隐藏组件 支持 不支持

二、实现思路

主要思想就是通过\color{red}{虚拟dom}虚拟dom占位各个节点,根据可显示视口的变化来展示该展示的节点。影响可显示视口的因素的监听,页面整体宽高变化、节点高度变化、页面的滚动定位到某一个节点等都可能会影响到视口的变化。当视口发生变化后计算可显示的节点,将可显示的节点挂载上节点的组件,不在视口内的节点销毁组件紧保留一个空的div。下图为实现思路的流程图。

三、关键方法源码分析

主入口html结构如下,\color{red}{v-for}v−for 展示长列表长度的的节点,并且通过:style 来设置一个\color{red}{最小高度}最小高度,设置最小高度的原因是这个高度值可能不准确,当真正组件渲染完之后计算出最准确的高度,如果直接height的话可能会使节点内的组件展示不全。同时每个节点设置唯一id(scrollItem_ 唯一标识),在根据数据获取dom信息时候使用。节点组件定义了唯一的class (long-item- 唯一标识),主要用来挂载真实列表组件,同时监听组件的高度变化。showList[index]来控制节点是否时候显示的唯一标识。

  <!--html代码-->
  <template>
    <div
      :
      :style="{'min-height': (item.height>=0?item.height:height) + 'px'}"
      :key="item[dataKey]"
      :id="'scrollItem_' + item[dataKey]"
      v-for="(item,index) in dataList"
      >
      <long-item
        v-if="showList[index]"
        :dataKey="dataKey"
        :item="item"
        :boxHeight="item.height||0"
        :direction="direction"
        :heightChange="heightChange"
        :extendCcomments="extendCcomments">
      </long-item>
    </div>
  </template>

当showList[index]为true的时候,对应的节点显示。long-item 在mounted生命周期时,回调extendCcomments。通过\color{red}{Vue.extend Profile}Vue.extendProfile挂载到对应的dom上。componentProps是节点组件传过来的一些参数,在挂载的时候全部挂载上。

 <!--挂载组件-->
  extendCcomments(item){
    this.componentProps.item=item
    var Profile = Vue.extend(this.dataComponent);
        // 创建 Profile 实例,并挂载到一个元素上
        new Profile({
          propsData:this.componentProps
        }
      ).$mount('.long-item-'+item[this.dataKey]);
  }

通过\color{red}{element-resize-detector}element−resize−detector来监听dom尺寸的变化,每个节点的宽高发生变化的时候,并且与原来的尺寸不一样回调heightChange方法,进行尺寸的更新及显示节点的操作计算。

 <!--每个节点尺寸发生变化-->
  this.$nextTick(()=> {
    this.$DomListener.listenTo(document.getElementById('long-item-'+this.item[this.dataKey]), (element)=>{
      if(this.boxHeight != element[this.directionConfig.width]){
        this.heightChange(this.item, element[this.directionConfig.width])
      }
    })
  });

获取可显示的视口区域的方法,页面滚动和尺寸变化都会调用到这个方法,所以这个方法在调用的时候做防抖处理300ms内有连续调用只会执行最后一次调用,要不然会频繁计算影响性能。可显示视口区域计算方式是当前视口 及 前后两个视口总共三个视口的尺寸。这样在小的滚动范围内会有较好的体验。

  getShowLimit(startTop) {
    const scrollTop = startTop || this.scrollWrap[this.directionConfig.scrollTo] || 0; // 滚动距离
    this.viewClientHeight = this.scrollWrap[this.directionConfig.width]; // 可视区域高度
    this.scrollTop = scrollTop
    this.showStart = scrollTop - this.viewClientHeight
    this.showEnd = scrollTop + 2*this.viewClientHeight
    if(this.setTopTimer){
      clearTimeout(this.setTopTimer)
    }
    this.setTopTimer = setTimeout(() => {
      this.setItemTopheight()
    }, 300);
  },

根据高度或者宽度来计算节点是否显示,因为这个计算量比较大避免而且这个方法与其他方法没有什么关联,直接单独开一个\color{red}{独立线程}独立线程进行计算。通过引入\color{red}{simple-web-worker}simple−web−worker这个插件单独开一个线程进行计算显示节点。计算方法主要有三点:当前节点的开头在显示视口内、当前节点的结尾在显示视口内、当前节点开头和结尾都不在显示视口内。分为这三种情况,只要满足一种情况,则该节点就显示在显示视口中。

  // 根据高度计算节点是否显示
  setItemTopheight(){
    let stsartId = this.dataList[0]&&this.dataList[0][this.dataKey]
    let startDom = stsartId && document.getElementById('scrollItem_'+stsartId)
    let startTop = startDom ? startDom[this.directionConfig.offset] : 0
    this.worker = this.$worker.run((dataList,showStart,showEnd, startTop,hideIds,dataKey,height) =>{
      let topHeight = startTop; // 题目顶部距离顶部距离
      let bottomHeight = 0; // 题目底部距离顶部距离
      let showList = []
      for(let i=0,len=dataList.length;i<len;i++){
        let item = dataList[i]
        if(hideIds.indexOf(item[dataKey]) != -1){
          showList[i] = false;
          continue;
        }
        bottomHeight = topHeight + (item.height>=0?item.height:height)
        // 判断 1.题目顶部在显示范围内 2.题目底部在显示范围内 3.题目顶部和底部都不在显示范围内
        if((topHeight>=showStart && topHeight<=showEnd)||
          (bottomHeight>=showStart && bottomHeight<=showEnd)||
          (topHeight<showStart && bottomHeight>showEnd) ){
          showList[i] = true}
         else{
          showList[i] = false
        }
        topHeight += ((item.height>=0?item.height:height));
      }
      return showList
    }, [this.dataList, this.showStart, this.showEnd, startTop, this.hideIds,this.dataKey,this.height])
    .then(res => {
      this.showList = res
    })
    this.worker = null
  },

四、使用方式

安装vue-long-list-load:

npm install vue-long-list-load --save

项目内调用

<long-list
 ref="vueLongList"
 dataKey='id'
 scrollWrap
 :dataList="dataList"
 :dataComponent="dataComponent"
 :componentProps="componentProps"
 height=100
 >
</long-list>

五、参数说明

参数 说明 类型 必填 可选值 默认值
scrollWrapId 列表滚动容器id string true — —
dataKey 节点数据内唯一键值 String true — —
dataList 列表数据 Array true 具体见下方说明 —
dataComponent 自定义的节点组件 — true — —
ref 调用组件内部方法 string false — —
direction 滚动方向 Number false 0:纵向,1横向 0
hideIds 列表中需要隐藏的节点 Array false 具体见下方说明 []
height 节点高度 Number false — 100
componentProps 节点组件要传递的参数 Object false — {}
scroll 滚动区域内滚动回调方法 Function false - —
resized 某个节点宽高发生变化回调方法 Function false 具体见下方说明

部分参数说明

  &lt;--假设 dataKey=id-->

  &lt;--列表中需要隐藏的节点-->
  hideIds:[1, 2]
  &lt;--列表数据 dataList 内 height 为 **Number**。-->
  dataList:[
    {id:1,height:100},
    {id:2,height:200},
    {id:3,height:300},
    {id:4,height:300},
    {id:5,height:300}
  ]

  &lt;--节点高度-->
  height:100
  &lt;--如果dataList的数据内有height值 不需要设置这个height-->
  &lt;--如果dataList 和 height 都不传递的话,默认为100 可能滚动略有卡顿;-->
  &lt;--建议在每个高度都不相同的时候通过dataList传递,都相同时候通过height传递-->

  &lt;--某个节点宽高发生变化回调方法 返回参数为id 与高度-->
  resized(id, height){ }

总结

项目中实践数据,基本每个节点至少500个dom节点,平均也在800个dom节点以上,用vue-long-list-load 不在渲染区域内的题目只会渲染2个dom节点。按正常800左右个dom节点的题目计算 一般渲染区域渲染的节点在9个左右,如果是n节点的列表 ,每次加载 dom操作都减少(n-9)x(800-2)个dom的渲染,如果\color{red}{1000个节点}1000个节点的列表每次加载和操作的时候相当于减少了\color{red}{726180}726180个dom节点的渲染。首次渲染还有修改后的重绘都大大减少了dom的渲染加快了加载速度提高了用户体验。 此方案已经在项目中实践一段时间,用户反馈很好。如果大家也有类似的场景需求,欢迎大家使用!交流!

以上就是如何让vue长列表快速加载的详细内容,更多关于vue 长列表快速加载的资料请关注我们其它相关文章!

赞 (0)

相关推荐

  • vue-列表下详情的展开与折叠案例

    如下所示: 功能描述 1.默认折叠,点击时展示全部数据 2.点击A项,A展开,之后有两种情况:①再次点击A,A折叠:②点击其他项,如B,这时B展开,A折叠 解决方式 1.给展开折叠图标添加一个样式,显示成动画效果 <div class="arrow" :class="{'open':showDetail === index}"></div> .arrow{ position absolute width: 0.6rem; height: 0.

  • 关于vue的列表图片选中打钩操作

    首先 css,美化checkbox样式,这一段代码拿过去可以直接用 label { font-size: 25px; cursor: pointer; position: absolute; top: -10px; right: 0px; z-index: 150; } label i { font-size: 15px; font-style: normal; display: inline-block; width: 18px; border-radius: 15px; height: 18

  • vue实现前端列表多条件筛选

    本文实例为大家分享了vue实现前端列表多条件筛选的具体代码,供大家参考,具体内容如下 1.先上图: 2.搜索条件绑定的数据是: filterForm:{ schoolName:'',//输入的学校名称 position:'',//选择的区域区域 schoolLevel:"",//选择的学校办别 }, schoolList:[ {schoolName:'青岛市实验高级中学',schoolLevel:"",position:'山东省青岛市城阳区硕阳路69号'}, {sc

  • vue v-for出来的列表,点击某个li使得当前被点击的li字体变红操作

    这里使用的是给被点击的li添加类名的方式 <template> <div class="person1"> <div v-for="(item,index) in lists" @click="clickAdd(index)" :key="index" :class="{red:i === index}"> <div>{{item.name}}</div

  • Vue实现一个无限加载列表功能

    一个需要判断的地方就是加载中再次触发滚动的时候,不要获取数据. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>列表无限加载</title> <style> * { margin: 0; padding: 0; } li { height: 50px; border-bottom: 1px s

  • vue实现点击按钮“查看详情”弹窗展示详情列表操作

    html: <template> <div> <Modal v-model="classStatus" width="900" title="详情:" :styles="{top: '80px'}"> <Table stripe class="task-table" :columns="columnsName4" :data="task

  • vue实现列表滚动的过渡动画

    本文实例为大家分享了Vue实现列表滚动过渡动画的具体代码,供大家参考,具体内容如下 效果图 失帧比较严重,在手机上效果更佳. 原理分析 这个滚动页面由两个部分布局(底部固定的Tab页面除外).一个是顶部的banner轮播,一个是下面的列表.这里的重点是做列表的动画,banner轮播的网上资料很多,请自行查找. 这个动画最重要的是在滚动中实时计算startIndex和endIndex,动画比较简单,就是scale和opacity的变化.向下滚动时,startIndex变小:向上滚动时,endInd

  • vue实现循环滚动列表

    本文实例为大家分享了vue实现循环滚动列表的具体代码,供大家参考,具体内容如下 1.安装 vue-seamless-scroll   实例文档链接 cnpm install vue-seamless-scroll --save 2.文件中引入,组件配置 import vueSeamlessScroll from 'vue-seamless-scroll' 3.使用 <template> <vue-seamless-scroll :data="CardPartsStatistic

  • vue 公共列表选择组件,引用Vant-UI的样式方式

    此组件用于公共选择组件.引用Vant UI 作为样式 特性: 1.支持动态.静态数据源. 2.支持分页加载. 3.支持模糊搜索. 4.支持单选.多选. 组件源码: <template> <div class="gn-PubSelect"> <van-action-sheet v-model="inShow"> <div class="gn-PubSelect-main" :style="{'he

  • Vue 列表页带参数进详情页的操作(router-link)

    首先,仔细看文档!!!一点一点的踩坑过来的~~~ 这里介绍params和query两种方法 1.用params传参 列表页: <router-link :to="{ name:'msgDetail', params: {id: item.msg_id} }">(注意:用params传参这里是命名路由,用name) </router-link> 路由配置如下: export default new Router({ routes: [ { path: '/msgD

随机推荐