JSFiddle - React, Tailwind, and code Playground

by tonyleeper

HTML

<div id="virtualised-list-container"></div>
<button id="dispose">dispose</button>
<button id="rows10">10 rows</button>
<button id="rows100">100 rows</button>
<button id="rows1000">1,000 rows</button>
<button id="rows10000">10,000 rows</button>
<button id="rows100000">100,000 rows</button>
<button id="rows1000000">1,000,000 rows</button>

CSS

html, body {
    font: 18px arial;
}

#virtualised-list-container {
    height: 200px;
    width: 300px;
    border: 1px solid black;
    overflow: auto;
}

#virtualised-list-container .cell {
    border-bottom: 1px solid lightgray;
    width: 100%;
}

JavaScript

var logger = {
    create: function () {
        this.element = document.createElement('div');
        this.element.setAttribute('style', 'position: fixed; right: 0; top: 0; border: 1px solid grey; background-color: lightyellow');
        document.body.appendChild(this.element);
    },
    log: function (what) {
        if (!this.element) {
            this.create();
        }  
        
        this.element.innerHTML = what;
    }
};

    //#region EventCoordinator

    var EventCoordinator = function (context) {
        this.context = context;
        this.registeredEventListeners = [];
    };
    
    EventCoordinator.prototype.register = function (element, type, listener, useCapture) {
        var listenerDefinition = {
            element: element,
            type: type,
            listener: listener.bind(this.context),
            useCapture: useCapture
        };
        this.registeredEventListeners.push(listenerDefinition);
        listenerDefinition.element.addEventListener(listenerDefinition.type, listenerDefinition.listener, listenerDefinition.useCapture);
    };

    EventCoordinator.prototype.dispose = function () {
        var listenerDefinition;
        while (this.registeredEventListeners.length > 0) {
            listenerDefinition = this.registeredEventListeners.pop();
            listenerDefinition.element.removeEventListener(listenerDefinition.type, listenerDefinition.listener, listenerDefinition.useCapture);
        }
    };

    //#endregion

var VirtualisedList = function (element, params) {
    this.element = element;
    this.renderItem = params.renderItem;
    this.items = params.items;
    this.init();
};

VirtualisedList.prototype.init = function () {
    this.cellHeight = this.getCellHeight(this.items[0]);
        
    this.element.classList.add('virtualised-list');
    this.element.setAttribute('style', 'position: relative');
    this.virtualScrollHeight = this.cellHeight * this.items.length;
    this.maxVirtualScrollTop =...