如何让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实现列表滚动的过渡动画

    本文实例为大家分享了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实现一个无限加载列表功能

    一个需要判断的地方就是加载中再次触发滚动的时候,不要获取数据. <!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的列表图片选中打钩操作

    首先 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 列表页带参数进详情页的操作(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

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

  • 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 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 公共列表选择组件,引用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

随机推荐