vue长列表优化之虚拟列表实现过程详解

标题:Vue长列表优化之虚拟列表实现过程详解

1. 前言

在处理Vue中长列表(包含大量子组件)时,当数据更新时,会造成较大的性能问题。因此,为了提高Vue应用的性能,我们通常会做一些长列表的优化。其中,虚拟列表技术是一种高效的长列表优化方法。本文旨在介绍Vue中如何利用虚拟列表技术实现长列表优化。

2. 虚拟列表实现过程详解

2.1 什么是虚拟列表

虚拟列表是指只渲染当前滚动区域内的子组件,而不是全部渲染。当用户滚动列表时,只有当前可见区域内的列表项才会被渲染,同时被滚动到可见区域外的列表项则会被销毁。这种做法不仅能够提高列表的渲染性能,同时也能够节省内存空间。

2.2 实现过程

2.2.1 计算总高度

虚拟列表的实现需要先计算出列表项总高度,以便后续做一些计算处理。

mounted() {
  // 计算每个列表项高度
  this.itemHeight = this.$refs.item[0].clientHeight
  // 计算列表总高度
  this.totalHeight = this.itemHeight * this.list.length
}

2.2.2 计算显示区域

然后我们需要计算出当前屏幕可见区域内的列表项。我们可以通过计算可视区域内第一项的索引来实现。

watch: {
  scrollTop(newVal) {
    this.start = Math.floor(newVal / this.itemHeight)
    // 为了避免底部区域不足一个完整的列表项高度而导致渲染的列表项不完整,需向下取整
    this.end = Math.ceil((newVal + this.visibleHeight) / this.itemHeight)
  }
}

2.2.3 渲染虚拟列表

接下来是实现虚拟列表的关键步骤,即在计算出显示区域后,只渲染这些显示区域内的列表项。为了实现这个目的,我们需要在模板中加入一个用来展示虚拟列表项的容器,然后根据计算出的start和end索引,只渲染这些需要展示的列表项。

<template>
  <div class="list-container" ref="listContainer" @scroll="onScroll">
    <div class="virtual-list" :style="{height: totalHeight + 'px', paddingTop: start * itemHeight + 'px', paddingBottom: (list.length - end) * itemHeight + 'px'}">
      <div class="item" v-for="(item, index) in list" :key="index" :ref="'item-' + index" :style="{top: index * itemHeight + 'px'}" v-show="index >= start && index < end">
        {{item}}
      </div>
    </div>
  </div>
</template>

关键部分是"v-show"指令,根据计算出的"start"和"end"索引,只渲染当前显示区域内的列表项。

3. 示例说明

3.1 示例1

实现一个包含10000个列表项的虚拟列表组件。其中,每个列表项是一个文本框,用户可以在里面输入内容。在用户在文本框中输入内容时,控制台将输出当前列表项的内容。

<template>
  <div class="list-container" ref="listContainer" @scroll="onScroll">
    <div class="virtual-list" :style="{height: totalHeight + 'px', paddingTop: start * itemHeight + 'px', paddingBottom: (list.length - end) * itemHeight + 'px'}">
      <div class="item" v-for="(item, index) in list" :key="index" :ref="'item-' + index" :style="{top: index * itemHeight + 'px'}" v-show="index >= start && index < end">
        <input type="text" placeholder="请输入内容" v-model="item" @input="onInput(index)">
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      list: [],
      itemHeight: 40,
      visibleHeight: 500 // 可视区域高度
    }
  },
  mounted() {
    this.initList()
  },
  methods: {
    initList() {
      // 初始化列表数据
      for (let i = 0; i < 10000; i++) {
        this.list.push('item' + i)
      }
      // 计算每个列表项高度
      this.itemHeight = this.$refs.item[0].clientHeight
      // 计算列表总高度
      this.totalHeight = this.itemHeight * this.list.length
    },
    onScroll() {
      // 计算当前可见区域的索引
      this.start = Math.floor(this.$refs.listContainer.scrollTop / this.itemHeight)
      this.end = Math.ceil((this.$refs.listContainer.scrollTop + this.visibleHeight) / this.itemHeight)
    },
    onInput(index) {
      // 输出列表项内容
      console.log(this.list[index])
    }
  }
}
</script>

此示例中,列表项使用input标签来展示,用户在输入内容时,控制台将输出当前列表项的内容。

3.2 示例2

实现一个包含100个图片的虚拟列表组件。其中,每个列表项是一个图片容器。当用户滚动列表时,用随机生成的颜色来填充图片,并展示在列表项中。

<template>
  <div class="list-container" ref="listContainer" @scroll="onScroll">
    <div class="virtual-list" :style="{height: totalHeight + 'px', paddingTop: start * itemHeight + 'px', paddingBottom: (list.length - end) * itemHeight + 'px'}">
      <div class="item" v-for="(item, index) in list" :key="index" :ref="'item-' + index" :style="{top: index * itemHeight + 'px'}" v-show="index >= start && index < end">
        <div class="img-container">
          <div class="img" :style="{backgroundColor: item.color}"></div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      list: [],
      itemHeight: 300,
      visibleHeight: 500 // 可视区域高度
    }
  },
  mounted() {
    this.initList()
  },
  methods: {
    initList() {
      // 初始化列表数据
      for (let i = 0; i < 100; i++) {
        this.list.push({color: this.getRandomColor()})
      }
      // 计算每个列表项高度
      this.itemHeight = this.$refs.item[0].clientHeight
      // 计算列表总高度
      this.totalHeight = this.itemHeight * this.list.length
    },
    onScroll() {
      // 计算当前可见区域的索引
      this.start = Math.floor(this.$refs.listContainer.scrollTop / this.itemHeight)
      this.end = Math.ceil((this.$refs.listContainer.scrollTop + this.visibleHeight) / this.itemHeight)

      // 更新列表项颜色,随机生成
      for (let i = this.start; i < this.end; i++) {
        this.$set(this.list[i], 'color', this.getRandomColor())
      }
    },
    getRandomColor() {
      // 生成随机颜色
      return '#' + Math.floor(Math.random() * 16777215).toString(16)
    }
  }
}
</script>

此示例中,列表项为图片容器,当用户滚动列表时,随机生成一个颜色来渲染图片,并展示在列表项中。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:vue长列表优化之虚拟列表实现过程详解 - Python技术站

(0)
上一篇 2023年5月29日
下一篇 2023年5月29日

相关文章

  • Vue将将后端返回的list数据转化为树结构的实现

    要将后端返回的list数据转化为树结构,我们可以通过Vue自带的方法或使用第三方库来实现。以下是两种实现方式: 方法一:使用Vue自带方法实现 Vue提供了一个$filter方法,可以用于筛选数组并返回新的数组。我们可以根据父子节点的关系,遍历list数据,将每个子节点添加到对应的父节点下面,最终得到树结构的数据。 示例代码如下: // 原始数据 let l…

    Vue 2023年5月29日
    00
  • vue实现pdf导出解决生成canvas模糊等问题(推荐)

    使用Vue实现PDF导出功能需要涉及到以下几个步骤: 安装依赖 npm install jspdf jspdf-autotable –save 引入jspdf和jspdf-autotable包 import jsPDF from ‘jspdf’ import ‘jspdf-autotable’ 编写导出PDF的方法 exportPdf() { // 新建一…

    Vue 2023年5月27日
    00
  • vue.js事件处理器是什么

    Vue.js 是一个流行的前端框架,具有响应式数据绑定、组件化等特性。在 Vue.js 中,事件处理器是指通过 v-on 指令绑定的方法。以下是详细讲解: 什么是 Vue.js 事件处理器? 在 Vue.js 中,v-on 指令被用于监听 DOM 事件,并在事件触发时执行相应的方法,这些方法就是事件处理器。v-on 指令有简写形式 @,例如 @click=”…

    Vue 2023年5月27日
    00
  • vue.js使用v-pre与v-html输出HTML操作示例

    请听我仔细地讲解。 1. 什么是Vue.js的v-pre指令? v-pre 是 Vue.js 中的一个特殊指令。它的作用是防止 Vue.js 在编译模板时对该元素进行处理,直接将元素渲染到页面上,以提高渲染效率。 下面是 v-pre 的使用方法: <template> <div v-pre>{{ message }}</div&…

    Vue 2023年5月27日
    00
  • 解决Babylon.js中AudioContext was not allowed to start异常问题

    在Babylon.js中播放音频时,有时会出现 “AudioContext was not allowed to start” 异常。这是由于浏览器启用了自动播放策略,导致无法正常启动AudioContext造成的。解决方法是在用户的交互行为中启动AudioContext。下面是解决这个问题的完整攻略: 1. 检查浏览器设置 首先,我们需要检查浏览器的设置,…

    Vue 2023年5月28日
    00
  • uniapp自定义弹框的方法

    下面我将详细讲解uniapp自定义弹框的方法。 1. 弹框组件编写 在uniapp项目中,我们可以自定义一个弹框组件,以实现自定义弹框的效果。首先,在components目录下创建一个名为customDialog的组件文件夹,然后将该组件注册到全局: // 在main.js中注册 import customDialog from ‘@/components/…

    Vue 2023年5月28日
    00
  • vue后端传文件流转化成blob对象,前端点击下载返回undefined问题

    首先,问题的原因是因为没有正确获取服务端传回的文件流,导致在前端的blob对象中无法处理正确的文件数据。此时,我们需要采用axios响应拦截器的方式进行解决。 步骤如下: 步骤一:后端返回流数据 在后端返回的接口中,返回的数据应为二进制流,如下示例: @GetMapping("/download") public ResponseEnti…

    Vue 2023年5月28日
    00
  • Vue2中配置Cesium全过程

    下面就详细讲解一下“Vue2中配置Cesium全过程”的完整攻略。 准备工作 在配置Vue2+ Cesium项目之前,需要先保证以下环境: 安装Node.js环境,并能够在终端使用Node和npm命令; 安装Vue CLI脚手架工具,可以运行下面的命令安装: npm install -g @vue/cli 安装完成后,可以通过运行 vue –version…

    Vue 2023年5月28日
    00
合作推广
合作推广
分享本页
返回顶部