fix(virtual-scroll): JSX can render headers and footers

This commit is contained in:
Manu Mtz.-Almeida
2018-05-10 17:17:33 +02:00
parent 50021cd0be
commit 012127dd7c
7 changed files with 67 additions and 44 deletions

View File

@ -260,11 +260,6 @@ and what data to give to the header template. The function must return
#### itemRender
#### items
@ -275,12 +270,22 @@ entire virtual scroll is reset, which is an expensive operation and
should be avoided if possible.
#### nodeHeight
#### nodeRender
#### renderer
#### renderFooter
#### renderHeader
#### renderItem
@ -364,11 +369,6 @@ and what data to give to the header template. The function must return
#### item-render
#### items
@ -379,12 +379,22 @@ entire virtual scroll is reset, which is an expensive operation and
should be avoided if possible.
#### node-height
#### node-render
#### renderer
#### render-footer
#### render-header
#### render-item

View File

@ -82,7 +82,7 @@
return el;
}
virtual.itemRender = (el, cell) => {
virtual.nodeRender = (el, cell) => {
if (cell.type === 0) return renderItem(el, cell.value);
return renderHeader(el, cell.value);
};

View File

@ -56,7 +56,7 @@
return el;
}
virtual.itemRender = (el, cell) => {
virtual.nodeRender = (el, cell) => {
if (cell.type === 0) return renderItem(el, cell.value);
return renderHeader(el, cell.value);
};

View File

@ -40,7 +40,6 @@ export interface VirtualNode {
const MIN_READS = 2;
export type NodeHeightFn = (node: VirtualNode, index: number) => number;
export type HeaderFn = (item: any, index: number, items: any[]) => string | null;
export type ItemHeightFn = (item: any, index?: number) => number;
export type ItemRenderFn = (el: HTMLElement|null, cell: Cell, domIndex?: number) => HTMLElement;
@ -104,7 +103,7 @@ export function updateVDom(dom: VirtualNode[], heightIndex: Uint32Array, cells:
export function doRender(
el: HTMLElement,
itemRender: ItemRenderFn,
nodeRender: ItemRenderFn,
dom: VirtualNode[],
updateCellHeight: Function
) {
@ -119,9 +118,9 @@ export function doRender(
if (node.change === NodeChange.Cell) {
if (i < childrenNu) {
child = children[i] as HTMLElement;
itemRender(child, cell, i);
nodeRender(child, cell, i);
} else {
child = itemRender(null, cell, i);
child = nodeRender(null, cell, i);
child.classList.add('virtual-item');
el.appendChild(child);
}

View File

@ -1,10 +1,10 @@
import { Component, Element, EventListenerEnable, Listen, Method, Prop, Watch } from '@stencil/core';
import { QueueController } from '../../interface';
import { Cell, DomRenderFn, HeaderFn, ItemHeightFn,
ItemRenderFn, NodeHeightFn, Range,
ItemRenderFn, Range,
VirtualNode, calcCells, calcHeightIndex, doRender,
findCellIndex, getRange, getShouldUpdate, getViewport,
inplaceUpdate, positionForIndex, resizeBuffer, updateVDom } from './virtual-scroll-utils';
inplaceUpdate, positionForIndex, resizeBuffer, updateVDom, CellType } from './virtual-scroll-utils';
@Component({
@ -98,11 +98,15 @@ export class VirtualScroll {
* should be avoided if possible.
*/
@Prop() items?: any[];
@Prop() renderer?: (item: any) => JSX.Element;
@Prop() nodeHeight?: NodeHeightFn;
@Prop() itemHeight?: ItemHeightFn;
@Prop() itemRender?: ItemRenderFn;
// JSX API
@Prop() renderItem?: (item: any, index: number) => JSX.Element;
@Prop() renderHeader?: (item: any, index: number) => JSX.Element;
@Prop() renderFooter?: (item: any, index: number) => JSX.Element;
// Low level API
@Prop() nodeRender?: ItemRenderFn;
@Prop() domRender?: DomRenderFn;
@Watch('itemHeight')
@ -255,11 +259,11 @@ export class VirtualScroll {
);
// write DOM
if (this.itemRender) {
doRender(this.el, this.itemRender, this.virtualDom, this.updateCellHeight.bind(this));
if (this.nodeRender) {
doRender(this.el, this.nodeRender, this.virtualDom, this.updateCellHeight.bind(this));
} else if (this.domRender) {
this.domRender(this.virtualDom);
} else if (this.renderer) {
} else if (this.renderItem) {
this.el.forceUpdate();
}
if (this.heightChanged) {
@ -370,24 +374,33 @@ export class VirtualScroll {
}
}
renderVirtualNode(node: VirtualNode) {
const cell = node.cell;
switch(cell.type) {
case CellType.Item: return this.renderItem!(cell.value, cell.index);
case CellType.Header: return this.renderHeader!(cell.value, cell.index);
case CellType.Footer: return this.renderFooter!(cell.value, cell.index);
}
}
render() {
const renderer = this.renderer;
if (renderer) {
return this.virtualDom.map((dom) => {
const item = renderer(dom.cell.value) as any;
const renderItem = this.renderItem;
if (renderItem) {
return this.virtualDom.map((node) => {
const item = this.renderVirtualNode(node) as any;
const classes = ['virtual-item'];
if (!item.vattrs) {
item.vattrs = {};
}
item.vattrs.class += ' virtual-item';
if (!dom.visible) {
if (!node.visible) {
classes.push('virtual-loading');
}
item.vattrs.class += ' ' + classes.join(' ');
if (!item.vattrs.style) {
item.vattrs.style = {};
}
item.vattrs.style['transform'] = `translate3d(0,${dom.top}px,0)`;
item.vattrs.style['transform'] = `translate3d(0,${node.top}px,0)`;
return item;
});
}