mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-24 14:58:36 +08:00
feat(virtual-scroller): add <template> support
This commit is contained in:
@ -30,67 +30,36 @@
|
||||
<p>
|
||||
<ion-button onclick="addItems()">Add Items</ion-button>
|
||||
</p>
|
||||
<ion-virtual-scroll id="virtual"></ion-virtual-scroll>
|
||||
|
||||
<ion-virtual-scroll id="virtual">
|
||||
<template>
|
||||
<ion-item>
|
||||
<ion-label></ion-label>
|
||||
</ion-item>
|
||||
</template>
|
||||
</ion-virtual-scroll>
|
||||
|
||||
<ion-infinite-scroll threshold="100px" id="infinite-scroll">
|
||||
<ion-infinite-scroll-content loadingSpinner="bubbles" loadingText="Loading more data...">
|
||||
</ion-infinite-scroll-content>
|
||||
</ion-infinite-scroll>
|
||||
|
||||
</ion-content>
|
||||
|
||||
|
||||
|
||||
</ion-app>
|
||||
|
||||
<script>
|
||||
const virtual = document.getElementById('virtual');
|
||||
const items = Array.from({ length: 100 }, (x, i) => i);
|
||||
|
||||
function addItems(append) {
|
||||
if (!append) {
|
||||
append = Array.from({ length: 10 }, (x, i) => "append" + i);
|
||||
}
|
||||
items.push(...append);
|
||||
virtual.markDirtyTail(append.length)
|
||||
}
|
||||
|
||||
virtual.itemHeight = () => 45;
|
||||
virtual.headerFn = (item, index) => {
|
||||
// if (index % 20 === 0) {
|
||||
// return 'Header ' + index;
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
function renderItem(el, item) {
|
||||
if (!el) {
|
||||
el = document.createElement('ion-item');
|
||||
const text = document.createTextNode(item);
|
||||
el['$content'] = text;
|
||||
el.appendChild(text);
|
||||
} else {
|
||||
el['$content'].nodeValue = item;
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
function renderHeader(el, item) {
|
||||
if (!el) {
|
||||
el = document.createElement('ion-item-divider');
|
||||
const text = document.createTextNode(item);
|
||||
el['$content'] = text;
|
||||
el.appendChild(text);
|
||||
} else {
|
||||
el['$content'].nodeValue = item;
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
virtual.nodeRender = (el, cell) => {
|
||||
if (cell.type === 0) return renderItem(el, cell.value);
|
||||
return renderHeader(el, cell.value);
|
||||
};
|
||||
const virtual = document.getElementById('virtual');
|
||||
virtual.itemHeight = () => 44;
|
||||
virtual.items = items;
|
||||
|
||||
virtual.nodeRender = (el, cell) => {
|
||||
if (cell.type === 0) {
|
||||
renderItem(el, cell.value);
|
||||
}
|
||||
};
|
||||
function renderItem(el, item) {
|
||||
el.querySelector('ion-label').textContent = item;
|
||||
}
|
||||
|
||||
|
||||
const infiniteScroll = document.getElementById('infinite-scroll');
|
||||
@ -103,6 +72,14 @@
|
||||
console.log('Done');
|
||||
});
|
||||
|
||||
function addItems(append) {
|
||||
if (!append) {
|
||||
append = Array.from({ length: 10 }, (x, i) => "append" + i);
|
||||
}
|
||||
items.push(...append);
|
||||
virtual.markDirtyTail(append.length)
|
||||
}
|
||||
|
||||
function getAsyncData() {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
|
@ -20,11 +20,20 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<ion-virtual-scroll id="virtual"></ion-virtual-scroll>
|
||||
|
||||
<ion-virtual-scroll id="virtual">
|
||||
<template>
|
||||
<ion-card>
|
||||
<ion-card-header>
|
||||
<ion-card-title>Card Header</ion-card-title>
|
||||
</ion-card-header>
|
||||
<ion-card-content class="content"></ion-card-content>
|
||||
</ion-card>
|
||||
</template>
|
||||
</ion-virtual-scroll>
|
||||
|
||||
</ion-content>
|
||||
|
||||
|
||||
|
||||
</ion-app>
|
||||
|
||||
<script>
|
||||
@ -38,14 +47,7 @@
|
||||
}
|
||||
|
||||
function renderItem(el, item) {
|
||||
if (!el) {
|
||||
el = document.createElement('ion-card');
|
||||
}
|
||||
el.innerHTML = `
|
||||
<ion-card-header>
|
||||
<ion-card-title>Card Header</ion-card-title>
|
||||
</ion-card-header>
|
||||
<ion-card-content>${item.content}</ion-card-content>`;
|
||||
el.querySelector('.content').textContent = item.content;
|
||||
return el;
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ export function doRender(
|
||||
dom: VirtualNode[],
|
||||
updateCellHeight: (cell: Cell, node: HTMLElement) => void
|
||||
) {
|
||||
const children = el.children;
|
||||
const children = Array.from(el.children).filter(n => n.tagName !== 'TEMPLATE');
|
||||
const childrenNu = children.length;
|
||||
let child: HTMLElement;
|
||||
for (let i = 0; i < dom.length; i++) {
|
||||
@ -88,9 +88,10 @@ export function doRender(
|
||||
child = children[i] as HTMLElement;
|
||||
nodeRender(child, cell, i);
|
||||
} else {
|
||||
child = nodeRender(null, cell, i);
|
||||
const newChild = createNode(el, cell.type);
|
||||
child = nodeRender(newChild, cell, i) || newChild;
|
||||
child.classList.add('virtual-item');
|
||||
el.appendChild(child);
|
||||
el.appendChild(child!);
|
||||
}
|
||||
(child as any)['$ionCell'] = cell;
|
||||
} else {
|
||||
@ -121,6 +122,22 @@ export function doRender(
|
||||
}
|
||||
}
|
||||
|
||||
function createNode(el: HTMLElement, type: CellType): HTMLElement | null {
|
||||
const template = getTemplate(el, type);
|
||||
if (template) {
|
||||
return el.ownerDocument.importNode(template.content, true).children[0] as HTMLElement;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getTemplate(el: HTMLElement, type: CellType): HTMLTemplateElement | null {
|
||||
switch (type) {
|
||||
case CellType.Item: return el.querySelector('template:not([name])');
|
||||
case CellType.Header: return el.querySelector('template[name=header]');
|
||||
case CellType.Footer: return el.querySelector('template[name=footer]');
|
||||
}
|
||||
}
|
||||
|
||||
export function getViewport(scrollTop: number, vierportHeight: number, margin: number): Viewport {
|
||||
return {
|
||||
top: Math.max(scrollTop - margin, 0),
|
||||
|
Reference in New Issue
Block a user