Giter Site home page Giter Site logo

dhilt / vscroll-native Goto Github PK

View Code? Open in Web Editor NEW
9.0 4.0 2.0 1.2 MB

Virtual scroll module for native javascript applications

Home Page: https://dhilt.github.io/vscroll-native/

License: MIT License

JavaScript 42.44% TypeScript 57.56%
javascript typescript virtual-scroll virtual-scroller virtual-list virtualscroll infinite-scroll scroll scrolling virtual

vscroll-native's Introduction

npm version

vscroll-native

vscroll-native is a JavaScript library built on top of the vscroll library to represent unlimited datasets using virtualization technique. The idea behind virtualization is to increase the performance of large scrollable lists by rendering only a small portion of the dataset, which is visible to the end user at a moment, while the rest of the dataset is emulated with special padding elements that keep the scrollbar parameters consistent, making the UX close to a simple scrollable list without virtualization.

Getting

CDN

<script src="https://cdn.jsdelivr.net/npm/vscroll-native"></script>
<script>
  const scroller = new VScrollNative.Scroller({...});
</script>

NPM

npm install vscroll-native
import { Scroller } from 'vscroll-native';

const scroller = new Scroller({...});

Usage

The vscroll-native module exports two entities: Scroller and Datasource. The virtual scroll engine runs during the Scroller class instantiation. The constructor of the Scroller class requires 3 arguments packed in a settings object: viewport HTML element, single item HTML template factory and the datasource.

import { Scroller, Datasource } from 'vscroll-native';

const element = document.getElementById('viewport');

const template = item =>
  `<div class="item"><span>${item.data.id}</span>) ${item.data.text}</div>`;

const datasource = new Datasource({
  get: (index, length, success) => {
    const data = [];
    for (let i = index; i <= index + count - 1; i++) {
      const item: Data = { id: i, text: 'item #' + i };
      data.push(item);
    }
    success(data);
  }
});

new Scroller({ element, datasource, template });

This basic example is available at https://dhilt.github.io/vscroll-native/samples/cdn/. Let's clarify what the Scroller is and how to instantiate it properly. In terms of the TypeScript the argument object of the Scroller constructor has the following type:

interface IScrollerParams<Data = unknown> {
  element: HTMLElement;
  template: Template<Data>;
  datasource: IDatasource<Data>;
}

1. Viewport

The first parameter of the Scroller is an HTML element that should provide the limited viewport with scrollable contents. It should be present in DOM before instantiating the Scroller.

const element = document.getElementById('viewport');
<div id="viewport"></div>
#viewport {
  height: 240px;
  width: 150px;
  overflow-y: scroll;
}

This is the simplest case with the default elements structure that is managed by the Scroller automatically.

2. Template

The second parameter of the Scroller is a factory of single item template. This is a function that should return a string that will be used by the Scroller to render items in the visible part of the viewport.

const template = ({ data }) =>
  `<div class="item"><span>${data.id}</span>) ${data.text}</div>`;

The argument of the template factory is an item object containing data to be present to the end user. With TypeScript it can be written as follows:

import { Template } from 'vscroll-native';

interface Data {
  id: number;
  text: string;
}

const template: Template<Data> = ({ data }) =>
  `<div class="item"><span>${data.id}</span>) ${data.text}</div>`;

3. Datasource

The third parameter of the Scroller is a special datasource object, providing dataset items in runtime. There are two ways of how it can be defined. First, as an object literal of IDatasource type:

import { IDatasource } from 'vscroll-native';

const datasource: IDatasource<Data> = { get, settings };

Second, as an instance of Datasource class, whose constructor requires an object of IDatasource type:

import { Datasource } from 'vscroll-native';

const datasource = new Datasource<Data>({ get, settings });

The second way makes the Adapter API available via datasource.adapter property after the Datasource is instantiated (see Adapter section). In both cases we need to arrange the object of IDatasource type:

interface IDatasource<Data = unknown> {
  get: DatasourceGet<Data>;
  settings?: Settings<Data>;
  devSettings?: DevSettings;
}

The settings parameter is optional (as well as devSettings), please refer to ngx-ui-scroll documentation to get more information about it: https://github.com/dhilt/ngx-ui-scroll#settings.

The get parameter is the main point of the App-Scroller integration. It should provide a portion of dataset by index and count:

const get = <Data = unknown>(
  index: number, count: number, success: (data: Data[]) => void
) => 
  success(Array.from({ length: count }).map((i, j) =>
    ({ id: index + j, text: 'item #' + (index + j) })
  ));

This is the simplest example of the synchronous Datasource.get implementation, where items are generated at runtime and passed to the Scroller via success callback. There are two additional signatures for asynchronous implementations: promise-based and observable-based.

const get = (index, count) => new Promise((resolve, reject) => {
  makeAjaxCall(index, count)
    .then(data => resolve(data))
    .catch(error => reject(error))
});
// should be equivalent to 
// const get = (index, count) => makeAjaxCall(index, count);
import { Observable } from 'rxjs';

const get = (index, count) => new Observable(subscriber => {
  makeAjaxCall(index, count)
    .then(data => subscriber.next(data))
    .catch(error => subscriber.error(error))
    .finally(() => subscriber.complete())
});

Adapter

Adapter is a special entity providing massive functionality to assess and manipulate Scroller's data/parameters at runtime. It is available if the Datasource is created via operator new.

import { Datasource, Scroller } from 'vscroll-native';

const ds = new Datasource({ ... });

ds.adapter.init$.once(() => console.log('Adapter works, the second output'));

new Scroller({ datasource: ds, ... });

console.log('Scroller works, the first output');

Note, that the adapter subscriptions become available right after instantiating the Datasource, but they start work only after the Scroller instantiation.

Please refer to the ngx-ui-scroll documentation for more information on the Adapter API: https://github.com/dhilt/ngx-ui-scroll#adapter-api. An important difference should be taken into account, this is how the reactive props are implemented:

  • ngx-ui-scroll Adapter implements RxJs subjects,
  • vscroll-native Adapter implements Reactive entities.

The vscroll-native demo contains some basic examples of the Adapter usage: https://dhilt.github.io/vscroll-native/.

Development

The vscroll-native module is built on top of the vscroll solution and can be treated as a vscroll wrapper or consumer. It is designed to demonstrate how the vscroll solution may work in non-specific environment. The sources of the vscroll-native module are relatively small (https://github.com/dhilt/vscroll-native/tree/main/src); they do

  • instantiate the virtual scrolling Workflow (main entity of the vscroll module),
  • advance DOM manipulations in accordance with the Workflow requirements,
  • provide some infrastructure logic such as internal Workflow instance storage and external Scroller class.

The issues, requests and ideas that are not targeting these particular points should be addressed to the vscroll repository.

The most important point of the development of the vscroll-native module is the DOM-related logic. Another important area is the demo app development. Also, the tests are very poor and need extension.

There are some npm scripts:

  • npm start, runs the demo app over the vscroll-native sources at 5000 port
  • npm run build, builds the vscroll-native distributive
  • npm run build-app, builds the demo app distributive
  • npm test, performs linter and tests in a single run
  • npm run jest, runs tests in a watch mode

2022 © Denis Hilt

vscroll-native's People

Contributors

dhilt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

vscroll-native's Issues

Feature: Flex Grid VScroll

Amazing work! I have been looking for a js vscroll solution, without any frameworks. And I ended up here. I tried the demo, and am largely satisfied with the current result. But when it comes to "multi-column" vscroll, most vscroll project just put it in the wip or gotcha section. But I think in my case, padding height of a flex css grid is calculatable.

I have a bunch of square containers with their parent has these css styles:

display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: flex-start;
gap: 20px;

How should I use this project? Do you have any suggestions for me?

Idea: ScrollerFactory() that allows alternate template type and renderer

I like this vscroll-native example. But I would like to use something different than innerHTML in createItemElement.

createItemElement is a fine default, but there would be some advantages if something like uhtml or lithtml were an option. (I prefer uhtml, but I am sure lithtml and others could be popular too.)

What if there was ScrollerFactory that is provided the desired renderer and returns a Scroller class with the applicable Template type for the renderer chosen?

  • The existing Scroller.prototype.createItemElement would be replaced with a createItemElement<TEMPLATE> that is provided to the ScrollerFactory and would have the same interface. But it would dictate the TEMPLATE type for the renderer used.
  • As a default, the provided createItemElement could be the same implementation as the existing Scroller.prototype.createItemElement, where the TEMPLATE generic would be set to the existing Template type.

Is this something you'd consider? If so, I am happy to see if this idea works and create a pull request. (I may have some flaws in my current thinking/idea, but my hope is that its mostly feasible and that I can work out problems if I pursue it.) I just want to proceed if the idea is not valued.

Alternatively I could use vscroll-native as an example and create my own implementation that uses my preferred renderer. But it feels like there is opportunity for reuse if there were a ScrollerFactory that provided the desired renderer.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.