Vue 虚拟列表的实战示例

序言

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

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

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

  • 译自 Better Programming
  • 在线 Demo

设计

咱还是用 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 虚拟列表的实战示例 的全部内容, 来源链接: utcz.com/p/238983.html

回到顶部