framework7io / framework7

Full featured HTML framework for building iOS & Android apps
http://framework7.io
MIT License
18.04k stars 3.23k forks source link

autoHeight VirtualList wrong heights when filtered #4168

Closed lokpro closed 1 year ago

lokpro commented 1 year ago

Describe the bug

autoHeight VirtualList calcs wrong heights when filtered.

How to reproduce

open the demo and do some searches: https://codesandbox.io/p/sandbox/upbeat-leaf-k22836?file=%2Fsrc%2Fjs%2Fapp.js&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A19%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A19%7D%5D

can see wrong heights of rows image image

code fix suggestion

https://github.com/framework7io/framework7/blob/7fe7720b4a37f90c95f8d247a1ab5e878040e476/src/core/components/virtual-list/virtual-list-class.js#L194 The i here should be replaced with value of data-virtual-list-index to fix the problem.

I've tried injecting this function in my demo app. it seems the problem can be fixed.

Framework7.VirtualList.prototype.setListSize = function(autoHeightRerender) {
    const vl = this;
    const items = vl.filteredItems || vl.items;
    if (!autoHeightRerender) {
        vl.pageHeight = vl.$scrollableParentEl[0].offsetHeight;
    }
    if (vl.dynamicHeight) {
        vl.listHeight = 0;
        vl.heights = [];
        for (let i = 0; i < items.length; i += 1) {
            const itemHeight = vl.params.height(items[i]);
            vl.listHeight += itemHeight;
            vl.heights.push(itemHeight);
        }
    } else if (vl.autoHeight) {
        vl.listHeight = 0;
        if (!vl.heights) vl.heights = [];
        if (!vl.heightsCalculated) vl.heightsCalculated = [];
        const renderedItems = {};
        vl.$itemsWrapEl.find(`[data-virtual-list-index]`).forEach((el) => {
            renderedItems[parseInt(el.getAttribute('data-virtual-list-index'), 10)] = el;
        });
        for (let i = 0; i < items.length; i += 1) {
            const virtualListIndex = items[i].virtualListIndex;  // <<<<<<<<<<
            const renderedItem = renderedItems[virtualListIndex]; // <<<<<<<<
            if (renderedItem) {
                if (!vl.heightsCalculated.includes(i)) {
                    vl.heights[i] = renderedItem.offsetHeight;
                    vl.heightsCalculated.push(i);
                }
            }
            if (typeof vl.heights[i] === 'undefined') {
                vl.heights[i] = 40;
            }
            vl.listHeight += vl.heights[i];
        }
    } else {
        vl.listHeight = Math.ceil(items.length / vl.params.cols) * vl.params.height;
        vl.rowsPerScreen = Math.ceil(vl.pageHeight / vl.params.height);
        vl.rowsBefore = vl.params.rowsBefore || vl.rowsPerScreen * 2;
        vl.rowsAfter = vl.params.rowsAfter || vl.rowsPerScreen;
        vl.rowsToRender = vl.rowsPerScreen + vl.rowsBefore + vl.rowsAfter;
        vl.maxBufferHeight = (vl.rowsBefore / 2) * vl.params.height;
    }

    if (vl.updatableScroll || vl.params.setListHeight) {
        vl.$itemsWrapEl.css({ height: `${vl.listHeight}px` });
    }
}

However, data-virtual-list-index in items is only available in my program, so this may need to be rewritten.