1. 程式人生 > 程式設計 >Vue 虛擬列表的實戰示例

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 庫。

Vue 虛擬列表的實戰示例

大量的 DOM 元素會使得我們的網頁非常“重”。當 DOM 元素超過 1500 至 2000 個的時候,頁面就開始又延遲,尤其是在小型的、效能差的裝置上尤為明顯。

想象一下,有一個無線滾動的頁面,你不斷的下拉,它實際上可能形成了上萬個 DOM 元素,每個元素程式設計客棧還包含子節點,這樣將消耗巨大的效能。

Virtual scrollers 正是來解決這個問題的。

如上圖,已經表示的很清楚了。列表分為可見區域和緩衝區域,超出這個範圍的列表 DOM 都將被刪除。

好啦,準備工作已就緒,Let`s get it!

www.cppcns.com

// 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",www.cppcns.comcontinue: "-||",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] == ""
    ? rDCHxJ""
    : 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 defhttp://www.cppcns.comault {
 // 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 ?

然後我們執行程式看效果:

Vue 虛擬列表的實戰示例

npm run dev

Vue 虛擬列表的實戰示例

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

小結

使用者不會希望每下拉十條結果就要等待新的十條結果加載出來!所以我們需要有緩衝區,還未下拉到底的時候就預判它到底然後提前載入。這便是絲滑體驗的核心。

當然不在檢視區和緩衝區的 DOM 都將被刪除,這也是頁面不形成大量 DOM 元素的精髓。

這樣動態的處理列表的確是程式設計人員的一種智慧和用心。

你可以把 專案 克隆到本地再體會一下。以上便是本次分享~

以上就是Vue 虛擬列表的實現示例的詳細內容,更多關於Vue 虛擬列表的資料請關注我們其它相關文章!