vue-virtual-scroll-list虚拟组件实现思路详解

yizhihongxing

以下是"vue-virtual-scroll-list虚拟组件实现思路详解"的攻略:

什么是vue-virtual-scroll-list

vue-virtual-scroll-list 是一个基于 Vue.js 的虚拟滚动列表组件。 它通过渲染一部分可见的滚动视图,并随着滚动将视图进行重用,从而提高了大型数据列表的性能。

如何使用vue-virtual-scroll-list

vue-virtual-scroll-list 的使用非常简单,只需要通过npm安装组件,然后在Vue组件内引用即可:

npm install vue-virtual-scroll-list --save
<template>
  <div>
    <virtual-scroll-list :size="50" :remain="10" :bench="20" :tolerance="0" :list="longList">
      <template slot-scope="{ item }">
        <div>{{ item }}</div>
      </template>
    </virtual-scroll-list>
  </div>
</template>

<script>
import VirtualScrollList from 'vue-virtual-scroll-list'

export default {
  components: {
    VirtualScrollList
  },
  data () {
    return {
      longList: [/* 一大堆数据 */]
    }
  }
}
</script>

上述代码中,我们先引入一个 VirtualScrollList 组件,然后在模板中使用这个组件,并通过 list 属性将数据传入组件中。在 <template> 中使用了 slot-scope 来对每一项数据 item 进行自定义渲染。

vue-virtual-scroll-list 的实现思路

vue-virtual-scroll-list 的实现非常巧妙,主要是通过一些算法和策略来实现的。下面我们就来详细解析一下其实现思路:

1. 准备工作

在渲染列表前,我们需要先定义一些参数。

  • scroll: 此参数是列表容器,通过获取此元素的 scrollTop 和 offsetHeight 属性来监测滚动位置和容器高度。
  • cache: 一个对象缓存了所有已经渲染的子元素,以及它们的位置和大小信息,后面滚动到哪里,都不需要重新渲染和计算这些子元素的大小和位置。
data() {
  return {
    scroll: null,
    cache: {
      start: 0,
      end: -1,
      size: 0
    },
  }
},
mounted () {
  this.scroll = this.$refs.outer // 获取滚动元素引用
  this.scroll.addEventListener('scroll', this.handleScroll) // 监听滚动时间
  this.animationFrame = window.requestAnimationFrame(this.handleScroll) // 强制渲染第一屏
  this.cache = this.initCache()
},
methods: {
  handleScroll() {/*...*/}
  initCache() {/*...*/}
}

2. 初次渲染

当组件第一次渲染时,我们不得不渲染出整个列表,并记录下每一个子元素的大小和位置信息。这一步会比较耗性能,但它只需要执行一次,所以耗时可以接受。

initCache() {
  const ref = this.$refs.content
  const total = this.list.length

  let heights = new Array(total)
  let positions = new Array(total)
  let accHeight = 0

  for (let i = 0; i < total; i++) {
    const height = ref.children[i].offsetHeight
    heights[i] = height
    positions[i] = accHeight
    accHeight += height
  }

  return {
    start: 0,
    end: this.bench, // 预切换点
    heights,
    positions,
    size: accHeight
  }
}

initCache 函数中,我们通过循环记录每一个子元素的高度和位置信息,然后存储在 cache 变量中。startend 表示当前页面中渲染的子元素范围,heightspositions 分别表示每一个子元素的高度和相对于滚动容器顶部的位置。

3. 视图切换

一旦列表开始滚动,就会触发 handleScroll 方法。我们会在这个方法中计算当前需要渲染的子元素范围,并将未滚动到的子元素从页面中移除。

handleScroll() {
  const { start, end, cache } = this.cache
  const outerHeight = this.scroll.offsetHeight
  const scrollTop = this.scroll.scrollTop
  const containerTop = this.$refs.wrapper.getBoundingClientRect().top
  const threshold = this.tolerance // 阀值

  let newStart = start
  let newEnd = end

  if (scrollTop < cache.positions[start] - containerTop) { // 向上拖拽
    newStart = this.findStartIndex(scrollTop - containerTop)
    if (newStart < start) { // 省去无效渲染
      newEnd = Math.min(
        Math.max(newStart + this.remain, end),
        cache.positions.length - 1
      )
    }
  } else if (scrollTop + outerHeight > cache.positions[end] - containerTop + threshold) { // 向下拖拽
    newEnd = this.findEndIndex(scrollTop + outerHeight - containerTop + threshold)
    if (newEnd > end) { // 省去无效渲染
      newStart = Math.max(
        Math.min(newEnd - this.remain, start),
        0
      )
    }
  }

  // 将未显示的元素移除
  for (let i = start; i < newStart; i++) {
    this.removeItem(i)
  }
  for (let i = end; i > newEnd; i--) {
    this.removeItem(i)
  }

  // 将可见元素添加到页面中
  for (let i = newStart; i < start; i++) {
    this.createItem(i)
  }
  for (let i = end + 1; i <= newEnd; i++) {
    this.createItem(i)
  }

  // 更新 cache
  if (newStart !== start || newEnd !== end) {
    this.cache = {
      start: newStart,
      end: newEnd,
      size: cache.size,
      positions: cache.positions,
      heights: cache.heights
    }
  }
},

handleScroll 方法中,首先会计算处于可视区域内的子元素范围(newStartnewEnd)。如果可见区域发生了变化,我们需要将未展示的子元素从页面中移除,然后将可见的子元素添加至页面中。

4. 子元素重用

现在,我们已经解决了需要渲染哪些元素的问题。但是,每次滚动到新的区域时,需要重新渲染子元素是非常低效的。为了优化这一点,我们需要通过重用先前已经渲染的子元素来实现。

removeItem(index) {
  const node = this.$refs.content.children[index]
  this.placeholder.appendChild(node)
  this.cache.size -= this.cache.heights[index]
},

createItem(index) {
  const node =
    this.$refs[this.slotName] &&
    this.$refs[this.slotName][index] &&
    this.$refs[this.slotName][index][0] // 找到对应列表项的索引,通过v-show控制是否显示
  if (!node) return
  this.placeholder.appendChild(node.cloneNode(true))
  this.cache.size += this.cache.heights[index]
},

removeItemcreateItem 方法中,我们分别将子元素从页面中移除和添加回页面。需要注意的是,每一个移除的子元素,都要从 cache.size 中减去其自身的高度;每一个添加的子元素,都要从 cache.size 中加上其自身的高度。

示例说明

  • 示例1:假设需要渲染 10000 条数据,采用传统的渲染方式,肯定会卡顿。而使用 vue-virtual-scroll-list 虚拟列表组件,只会渲染出当前可视区域的元素,因此性能会大大提升。
  • 示例2:为了方便入门学习,我们可以参考 vue-virtual-scroll-list 源码,自己编写一个类似的虚拟列表组件。不仅能更深入理解其实现原理,还能够定制化更各式各样的外观和功能。

总结

以上就是 vue-virtual-scroll-list 虚拟列表组件的实现思路和代码示例。虽然组件实现思路有些复杂,但是通过实现,可以高效地渲染大量数据。在后续的开发过程中,可以参考和借鉴这样的思路,来处理大量数据的显示问题。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:vue-virtual-scroll-list虚拟组件实现思路详解 - Python技术站

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

相关文章

  • 基于vue2框架的机器人自动回复mini-project实例代码

    下面是针对“基于vue2框架的机器人自动回复mini-project实例代码”的详细攻略: 1. 环境搭建 首先,我们需要搭建好vue2的项目基础环境。可以通过如下命令创建一个vue2项目: vue create robot-reply-project 然后,进入项目目录cd robot-reply-project,安装一些需要的依赖: npm i axio…

    Vue 2023年5月28日
    00
  • 解析如何自动化生成vue组件文档

    下面是我给出的“解析如何自动化生成vue组件文档”的完整攻略,包含以下四个步骤: 步骤一:安装依赖 首先,我们需要安装一些必要的依赖: vue-docgen-api:生成 vue 组件的元数据 vue-styleguidist:将 vue 组件元数据输出为文档网站 你可以使用以下命令安装依赖: npm install vue-docgen-api vue-s…

    Vue 2023年5月27日
    00
  • 从Vuex中取出数组赋值给新的数组,新数组push时报错的解决方法

    对于从Vuex中取出数组赋值给新的数组,在进行push操作时报错通常是因为新数组被赋值时使用了浅拷贝,这会导致新数组和旧数组指向同一块内存地址,在新数组push时会影响到原来的数组,从而导致该错误的产生。以下是完整的解决方法攻略: 1.使用深拷贝 使用深拷贝可以解决浅拷贝的问题。在JavaScript中可以使用JSON.parse(JSON.stringif…

    Vue 2023年5月28日
    00
  • Vue的Eslint配置文件eslintrc.js说明与规则介绍

    Vue的Eslint配置文件(eslintrc.js)是用来规范Vue项目代码风格和优化代码质量的重要配置文件。本文将详细讲解该配置文件的说明和规则介绍,包括ESLint的安装、配置文件的基本配置、插件的安装和规则的介绍。 ESLint安装 要使用ESLint,首先需要在项目中安装ESLint模块,可以使用npm或yarn进行安装。 npm install …

    Vue 2023年5月28日
    00
  • VueJs 搭建Axios接口请求工具

    VueJs 搭建 Axios 接口请求工具可以分为以下几个步骤: 1. 安装 Axios 首先,在 VueJs 中使用 Axios 需要先安装 Axios 库。可以使用 npm 命令进行安装(前提是已经安装了 npm): npm install axios 2. 创建请求服务 可以在 Vue 项目中新建一个 services 文件夹,在其中创建 api.js…

    Vue 2023年5月28日
    00
  • 从0开始学Vue

    从0开始学Vue的完整攻略 Vue是一个流行的JavaScript框架,用于开发现代Web应用程序。如果你想完全掌握Vue,以下是从0开始学Vue的完整攻略。以下步骤将帮助您开始学习Vue并掌握Vue的基础知识。 步骤1: 学习前提 在学习Vue之前,您需要具备以下先验知识: 基本的HTML和CSS知识 基本的JavaScript语法 如果您还没有掌握这些知…

    Vue 2023年5月27日
    00
  • vue项目中自动导入svg并愉快的使用方式

    Vue项目中自动导入SVG并愉快的使用方式的攻略需要涉及到以下几个步骤: 1. 安装相关依赖 svg-sprite-loader:用于对SVG进行打包处理,将SVG图标精灵化。 svgo-loader:对SVG进行压缩和优化,减少SVG的文件大小。 npm install svg-sprite-loader svgo-loader -D 2. 配置webpa…

    Vue 2023年5月28日
    00
  • vue-cli脚手架build目录下utils.js工具配置文件详解

    接下来我将详细讲解 vue-cli 脚手架中 build 目录下的 utils.js 工具配置文件。 一、简介 utils.js 文件是 vue-cli 脚手架中 build 目录下的一个工具配置文件。该文件主要用于定义构建(build)过程中需要用到的各种工具函数。这些工具函数包含了一些实用的功能,例如:格式化输出字符串、合并路径、生成文件hash值等。 …

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