Vue 虚拟列表的实战示例

 更新时间:2021年03月18日 09:46:47   作者:掘金安东尼  
这篇文章主要介绍了Vue 虚拟列表的实现示例,帮助大家更好的理解和学习使用vue,感兴趣的朋友可以了解下

序言

现如今,我们总是在无止境的刷。刷微博、刷抖音、刷沸点......一次次丝滑下拉体验的背后却是前端攻城狮的用心。

本篇讨论基于 Vue.js 的列表无限下拉实践。

我们的目标就是:让列表下拉纵享丝滑,而不是像以往的下拉就 loading 等待的体验。

设计

咱还是用 Vue CLI 来快速构建项目。

这是主页面:

// EndlessList.vue

<template>
 <div class="endless-scrolling-list">
  <!-- 搜索框 -->
  <div class="search-box">
   <input type="text" v-model="searchQuery"/>
  </div>
  <p class="center" v-if="results.length == 0 && !loading">
   Start typing to search something.
  </p>
  <!-- 虚拟列表 -->
  <virtual-list
   :data-key="'pageid'"
   :data-sources="results"
   :data-component="itemComponent"
   :page-mode="true"
   />
  <!-- loading -->
  <loader v-if="loading" />
 </div>
</template>

其中核心当然是virtual-list组件啦~

这里的虚拟列表,我们用到一个三方库 Vue Virtual Scroll List,它在 Github 上又 2.5k+ 的 stars。类比于 react 的 react-virtualized 库。

大量的 DOM 元素会使得我们的网页非常“重”。当 DOM 元素超过 1500 至 2000 个的时候,页面就开始又延迟,尤其是在小型的、性能差的设备上尤为明显。

想象一下,有一个无线滚动的页面,你不断的下拉,它实际上可能形成了上万个 DOM 元素,每个元素还包含子节点,这样将消耗巨大的性能。

Virtual scrollers 正是来解决这个问题的。

如上图,已经表示的很清楚了。列表分为可见区域和缓冲区域,超出这个范围的列表 DOM 都将被删除。

好啦,准备工作已就绪,Let`s get it!

实现

// imports.js(EndlessList.vue)

import axios from 'axios';
import lodash from 'lodash';
import VirtualList from 'vue-virtual-scroll-list';
import SearchResult from './SearchResult';
import Loader from './Loader';
export default {
 name: 'EndlessList',
 components: {
  VirtualList,
  Loader
 },
 data() {
  return {
   searchQuery: '',
   currentPage: 0,
   results: [],
   itemComponent: SearchResult,
   loading: false
  }
 },
};

我们引入第三方库 axios 和 loadsh,以便后续使用。

其中,itemComponent 是 virtual-list 的属性,为此我们需要新建一个 SearchResult 子组件,作为搜索结果单元。

代码如下:

// SearchResult.vue

<template>
 <div class="list-item">
  <h3>
   {{ source.title }}
  </h3>
  <div v-html="source.snippet"></div>
 </div>
</template>

<script>
export default {
 props: {
  index: {
   // index of current item
   type: Number,
  },
  source: {
   type: Object,
   default() {
    return {};
   },
  },
 },
};
</script>

<style scoped>
.list-item {
 padding: 0 10px 20px 10px;
}
.list-item h3 {
 margin: 0;
 padding-bottom: 10px;
}
</style>

我们可以通过搜索标题或描述来得到结果,请求数据来源于维基百科。

search(query, page) {
 // We prepare the data that the Wikipedia API expects.
 const data = {
  action: "query",
  format: "json",
  list: "search",
  continue: "-||",
  utf8: 1,
  srsearch: query,
  sroffset: page * 10,
  origin: "*",
 };
 // And then we convert these params TO GET params in the format
 // action=query&format=json ...
 const params = Object.keys(data)
  .map(function(k) {
   return data[k] == ""
    ? ""
    : encodeURIComponent(k) + "=" + encodeURIComponent(data[k]);
  })
  .join("&");
 // We prepare the url with the params string
 const searchUrl = `https://en.wikipedia.org/w/api.php?${params}`;
 // we set loading to true so that we can display the loader 
 this.loading = true;
 // Then we execute the request and concatenate the results
 axios.get(searchUrl).then((response) => {
  this.results = this.results.concat(response.data.query.search);
  // And of course set loading to false to hide the loader.
  this.loading = false;
 });
}

搜索的方法已经写好,接着就是调用。

  1. 当用户键入内容的搜索时候会调用。
  2. 当下拉的时候会调用。

// EndlessList.vue

<script>
export default {
 // data() and methods skipped for brevity
 watch: {
  searchQuery: {
   immediate: true,
   handler: lodash.debounce(function (newVal) {
    if (newVal == "") {
     return;
    }
    this.results = [];
    this.currentPage = 0;
    this.search(newVal, this.currentPage);
    this.search(newVal, this.currentPage + 1);
    this.currentPage = 2;
   }, 200),
  },
 },
 mounted() {
  const vm = this;
  window.onscroll = lodash.debounce(function () {
   var distanceFromBottom =
    document.body.scrollHeight - window.innerHeight - window.scrollY;
   if (distanceFromBottom < 400 && vm.searchQuery !== "") {
    vm.search(vm.searchQuery, vm.currentPage);
    vm.currentPage++;
   }
  }, 100, {leading: true});
 },
}
</script>

显而易见,当 searchQuery 变化的时候,我们会得到新的搜索结果。当然,这里的输入框也用到了防抖函数。

另一个需要注意的是,我们第一次搜索加载了两页的结果,用户就会有一定的滚动空间,这样就可以保持顺畅的感觉。

我们在滚动的事件中也加了防抖函数。这里设一个疑问:为什么要在 window.onscroll 事件下设置 leading 为 true ?

然后我们运行程序看效果:

npm run dev

如何?只要你不是疯狂下拉,基本上感受不到 loading 的过程~

小结

用户不会希望每下拉十条结果就要等待新的十条结果加载出来!所以我们需要有缓冲区,还未下拉到底的时候就预判它到底然后提前加载。这便是丝滑体验的内核。

当然不在视图区和缓冲区的 DOM 都将被删除,这也是页面不形成大量 DOM 元素的精髓。

这样动态的处理列表的确是编程人员的一种智慧和用心。

你可以把 项目 克隆到本地再体会一下。以上便是本次分享~

以上就是Vue 虚拟列表的实现示例的详细内容,更多关于Vue 虚拟列表的资料请关注脚本之家其它相关文章!

相关文章

  • Vue核心概念Action的总结

    Vue核心概念Action的总结

    今天小编就为大家分享一篇关于Vue核心概念Action的总结,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01
  • vue + typescript + video.js实现 流媒体播放 视频监控功能

    vue + typescript + video.js实现 流媒体播放 视频监控功能

    视频才用流媒体,有后台实时返回数据, 要支持flash播放, 所以需安装对应的flash插件。这篇文章主要介绍了vue + typescript + video.js 流媒体播放 视频监控,需要的朋友可以参考下
    2019-07-07
  • Vue实现导出excel表格功能

    Vue实现导出excel表格功能

    这篇文章主要介绍了Vue实现导出excel表格的功能,在文章末尾给大家提到了vue中excel表格的导入和导出代码,需要的朋友可以参考下
    2018-03-03
  • Vue3中的执行流程思路分析-流程图

    Vue3中的执行流程思路分析-流程图

    这篇文章主要介绍了Vue3中的执行流程思路分析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • vue中使用element ui的弹窗与echarts之间的问题详解

    vue中使用element ui的弹窗与echarts之间的问题详解

    这篇文章主要介绍了vue中使用element ui的弹窗与echarts之间的问题详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • 移动端滑动切换组件封装 vue-swiper-router实例详解

    移动端滑动切换组件封装 vue-swiper-router实例详解

    这篇文章主要介绍了移动端滑动切换组件封装 vue-swiper-router实例详解,需要的朋友可以参考下
    2018-11-11
  • vue踩坑记-在项目中安装依赖模块npm install报错

    vue踩坑记-在项目中安装依赖模块npm install报错

    这篇文章主要介绍了vue踩坑记-在项目中安装依赖模块npm install报错,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • Vue+scss白天和夜间模式切换功能的实现方法

    Vue+scss白天和夜间模式切换功能的实现方法

    这篇文章主要介绍了Vue+scss白天和夜间模式切换功能的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • 在VUE中使用lodash的debounce和throttle操作

    在VUE中使用lodash的debounce和throttle操作

    这篇文章主要介绍了在VUE中使用lodash的debounce和throttle操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • vue中使用geobuf的示例详解

    vue中使用geobuf的示例详解

    这篇文章主要介绍了vue中使用geobuf的示例详细,本文结合示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04

最新评论