mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-15 17:42:15 +08:00
fix(virtual-scroll): JSX can render headers and footers
This commit is contained in:
@ -17,10 +17,10 @@ export class VirtualScroll {
|
||||
private el: ElementRef,
|
||||
public cd: ChangeDetectorRef,
|
||||
) {
|
||||
this.el.nativeElement.itemRender = this.itemRender.bind(this);
|
||||
this.el.nativeElement.nodeRender = this.nodeRender.bind(this);
|
||||
}
|
||||
|
||||
private itemRender(el: HTMLElement|null, cell: any, index?: number) {
|
||||
private nodeRender(el: HTMLElement|null, cell: any, index?: number) {
|
||||
if (!el) {
|
||||
const node = this.itmTmp.viewContainer.createEmbeddedView(
|
||||
this.getComponent(cell.type),
|
||||
|
15
core/src/components.d.ts
vendored
15
core/src/components.d.ts
vendored
@ -99,7 +99,6 @@ import {
|
||||
HeaderFn,
|
||||
ItemHeightFn,
|
||||
ItemRenderFn,
|
||||
NodeHeightFn,
|
||||
} from './components/virtual-scroll/virtual-scroll-utils';
|
||||
|
||||
declare global {
|
||||
@ -7213,16 +7212,17 @@ declare global {
|
||||
*/
|
||||
'headerFn': HeaderFn;
|
||||
'itemHeight': ItemHeightFn;
|
||||
'itemRender': ItemRenderFn;
|
||||
/**
|
||||
* The data that builds the templates within the virtual scroll. It's important to note that when this data has changed, then the entire virtual scroll is reset, which is an expensive operation and should be avoided if possible.
|
||||
*/
|
||||
'items': any[];
|
||||
'markDirty': (offset: number, len?: number) => void;
|
||||
'markDirtyTail': () => void;
|
||||
'nodeHeight': NodeHeightFn;
|
||||
'nodeRender': ItemRenderFn;
|
||||
'positionForItem': (index: number) => number;
|
||||
'renderer': (item: any) => JSX.Element;
|
||||
'renderFooter': (item: any, index: number) => JSX.Element;
|
||||
'renderHeader': (item: any, index: number) => JSX.Element;
|
||||
'renderItem': (item: any, index: number) => JSX.Element;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7267,13 +7267,14 @@ declare global {
|
||||
*/
|
||||
'headerFn'?: HeaderFn;
|
||||
'itemHeight'?: ItemHeightFn;
|
||||
'itemRender'?: ItemRenderFn;
|
||||
/**
|
||||
* The data that builds the templates within the virtual scroll. It's important to note that when this data has changed, then the entire virtual scroll is reset, which is an expensive operation and should be avoided if possible.
|
||||
*/
|
||||
'items'?: any[];
|
||||
'nodeHeight'?: NodeHeightFn;
|
||||
'renderer'?: (item: any) => JSX.Element;
|
||||
'nodeRender'?: ItemRenderFn;
|
||||
'renderFooter'?: (item: any, index: number) => JSX.Element;
|
||||
'renderHeader'?: (item: any, index: number) => JSX.Element;
|
||||
'renderItem'?: (item: any, index: number) => JSX.Element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
Reference in New Issue
Block a user