fergald / virtual-scroller-demos

Demos of the <virtual-scroller> element
Other
10 stars 2 forks source link

Making items virtualized without taxing the DOM with thousands of elements. #6

Closed trusktr closed 4 years ago

trusktr commented 4 years ago

Something I'm thinking is that if we write

<virtual-scroller id='scroller'>
  <div>Item 1</div>
  <div>Item 2</div>
  ...
  <div>Item 1000</div>
</virtual-scroller>

then we will be taxing the DOM system by adding so many elements (JS engine having to cross into the DOM engine, etc).

What virtual scrollers in frameworks like React, etc, do is they do not stick all elements into the DOM, they only stick (for example) 10 or 20 elements at a time depending on where we are scrolled to.

So if the virtual-scroller scroller API will need to have all 10,000 elements appended to the DOM, this will already be super heavy and expensive compared to other solutions.

I imagine virtual-scroller (at least in the polyfilled implementation) would need to set properties like visibility: hidden or display: none and keep track of layout, etc. This may be heavy for thousands of elements (compared to the libs).

Can we instead make it an API where we can specify data items (an array) and tell it what to render for each item, f.e. something like

<virtual-scroller id='scroller' element="div" for-each="(el, index) => el.textContent = someArray[index].name" item-width="100%" item-height="40px"></virtual-scroller>

This way, the inner DOM of virtual-scroller is entirely virtualized by being represented with non-DOM data (f.e. someArray of data in this case), and only 10 or 20 of the elements specified by element="" are placed into the DOM at a time, and the for-each is a function that takes each DOM element created and applies data to it from the array.

It would then be possible that authors could use React, Vue, jQuery, etc, within the for-each to apply the data to each element.

In a JS environment, we could also avoid global scoping of the for-each attribute, f.e.

const virtualScroller = document.querySelector('virtual-scroller')
const someArray = [...] // 10,000 items in here
virtualScroller.forEach = (el, index) => el.textContent = someArray[index].name

where now the function has lexical scope instead of global scope (similar to onclick, etc, attributes).

With something like a virtualScroller.forEach feature to describe the data manipulation for each element, then a JSX user (f.e.) could write

const someArray = [...] // 10,000 items in here
// ...
return <virtual-scroller forEach={(el, index) => el.textContent = someArray[index].name} />

They'd still enjoy their framework of choice, but let the virtual scrolling be handled natively.

fergald commented 4 years ago

Having the elements in the DOM is an explicit goal. Elements not in the DOM are not indexable, findable with ctrl-f or accessible to screenreaders etc.

https://github.com/WICG/virtual-scroller/blob/master/README.md#why-a-virtual-scroller

There are lots of existing virtual scrollers that do exactly what you're proposing.