Web長列表的救星?谷歌推出Virtual Scroller[轉]
原文連結:mp.weixin.qq.com
譯者|無明編輯|覃雲在剛剛結束的 Chrome dev summit 2018 上,谷歌工程經理 Gray Norton 向我們介紹 virtual-scroller,一個 Web 滾動元件,未來它可能會成為 Web 高層級 API(Layered API)的一部分。它的目標是解決長列表的效能問題,消除離屏渲染。該專案處於研發中,你可以在 GitHub 檢視它的開發者預覽版本。
眾所周知,渲染效能主要取決於渲染量, 過多的 DOM 會使你的網站速度變得很慢,即使在本地,也會出現相同的問題,但若通過虛擬滾動的方式,也就是在使用者滾動時用足夠的內容填充螢幕並不斷更新,就能讓網站保持高速執行,這也是 virtual-scroller 的基本原理。
詳解 virtual-scroller
<virtual-scroller>
是未來 Web 平臺的一個潛在特性,是 layered API 專案的一部分,用於將 JavaScript 物件集對映到 DOM 節點上,並且只渲染當前可見的 DOM 節點,其餘部分為“虛擬”的。
示例
<script type="module" src="std:virtual-scroller|https://some.cdn.com/virtual-scroller.js"> </script> <virtual-scroller></virtual-scroller> <script type="module"> const scroller = document.querySelector('virtual-scroller'); const myItems = new Array(200).fill('item'); scroller.updateElement = (child, item, index) => { child.textContent = index + ' - ' + item; child.onclick = () => console.log(`clicked item #${index}`); }; // This will automatically cause a render of the visible children // (i.e., those that fit on the screen). scroller.itemSource = myItems; </script>
預設情況下,這個示例中建立的虛擬滾動條內的元素為<div>
,並將會被回收。更多示例請參閱:
https://github.com/valdrinkoshi/virtual-scroller/blob/master/demo/index.html
virtual-scroller demo
API 介紹
createElement 屬性
型別:function(item: any, itemIndex: number) => Element
在設定這個屬性時,使用工廠函式來配置虛擬滾動條,這個工廠函式會在指定索引位置的專案首次準備好在 DOM 中顯示時建立一個元素。
在首次呼叫時,createElement 將搜尋第一個<template>
元素,該元素本身在其模板內容中至少也包含了一個子元素。如果存在,它將通過克隆該子元素來建立新元素。否則,它將建立一個<div>
元素。對於這兩種情況,如果 recycleElement 為預設值,它將回收 DOM 節點。
如果 recycleElement 為預設值,那麼更改這個屬性的預設值將自動將 recycleElement 重置為 null。
updateElement 屬性
型別:function(child: Element, item: any, itemIndex: number)
在設定這個屬性時,使用一個函式來配置虛擬滾動條,這個函式將使用指定索引處的專案的資料來更新元素。
這個屬性將在以下場景中被呼叫:
-
使用者滾動滾動條,更改專案元素的可見性。在這種情況下,將為所有新的可見元素呼叫 updateElement。
-
開發人員修改了 itemSource 屬性。
-
開發人員呼叫了 itemsChanged(),它將為所有當前可見的元素呼叫 updateElement。
預設的 updateElement 將子元素的 textContent 設定為給定項。幾乎所有使用的地方都需要改變這個行為。
recycleElement 屬性
型別:function(child: Element, item: any, itemIndex: number)
如果專案的元素不再可見,recycleElement 預設會將它回收,並將其與 DOM 連線,預設的 createElement 就可以重用它。
當專案元素不再可見時,將這個屬性設定為 null 可以將它從 DOM 中刪除,並防止被預設的 createElement 回收。
通常,這個屬性會被自定義,以便引入自定義的節點回收邏輯。
itemSource 屬性
型別:Array 或 ItemSource
設定這個屬性可以控制滾動條如何將可見索引對映到對應項。然後,這些項被提供給各種自定義渲染函式:createElement、updateElement、recycleElement。
如果提供的是陣列,它將被轉換為 ItemSource 例項,這個例項將返回陣列中的元素,就像在呼叫 ItemSource.fromArray(array) 一樣(沒有 key 引數)。
layout 屬性
型別:string
值可以為:
-
“vertical”(預設);
-
“horizontal”;
-
“vertical-grid”;
-
“horizontal-grid”。
也可以設定為元素的屬性,例如<virtual-scroller layout=“horizontal-grid"></virtual-scroller>
。
itemsChanged() 方法
這將重新渲染所有當前顯示的元素,使用 updateElement 來更新它們。
通常需要在要顯示的資料發生變化時呼叫它,包括對資料的新增、刪除和修改。
scrollToIndex 方法
要滾動到指定的索引,可選擇使用以下位置之一:
-
“start”:將專案的開頭與滾動條可見部分的開頭對齊;
-
“center”:將專案的中心與滾動條可見部分的中心對齊;
-
“end”:將專案的末尾與滾動條可見部分的末尾對齊;
-
“nearest”:如果專案位於滾動條可見部分的中心之前,那麼與“start”一樣;如果它位於滾動條可見部分的中心之後,則與“end”一樣。
“rangechange”事件
Bubbles: false / Cancelable: false / Composed: false
當滾動條完成渲染新的專案範圍時觸發,例如,使用者滾動了滾動條。這個事件是 RangeChangeEvent 的一個例項,它具有以下屬性:
-
first:一個數字,給出當前渲染的第一個專案的索引。
-
last:一個數字,給出當前渲染的最後一個專案的索引。
ItemSource 類
ItemSource 類代表了一種將索引轉換為 JavaScript 值的方法。你可以像這樣建立它們:
const source = new ItemSource({ item(index) { ... }, getLength() { ... }, key(index) { ... } });
例如,要建立一個從 contacts 陣列中獲取專案的 ItemSource,並使用 contact.id 作為鍵,你可以這樣:
const contactsSource = new ItemSource({ item(index) { return contacts[index]; }, getLength() { return contacts.length; }, key(index) { return contacts[index].id; } });
還有一個工廠方法 ItemSource.fromArray(array [,key]) 可以更容易地完成這個操作:
const contactsSource = ItemSource.fromArray(contacts, c => c.id);
將一個專案傳給 fromArray() 的引數 key,並且返回該物件的唯一鍵。如果沒有指定引數 key,則將專案索引作為鍵。
ItemSource 類的主要用途是賦值給<virtual-scroller>
元素的 itemSource 屬性,所以目前它唯一的公共 API 中只有一個 length 屬性。
參考連結:https://github.com/valdrinkoshi/virtual-scroller