mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
fix(): update to Stencil One 🎉🎊
This commit is contained in:
@ -97,6 +97,9 @@ kill its performance is to perform any DOM operations within section header
|
||||
and footer functions. These functions are called for every record in the
|
||||
dataset, so please make sure they're performant.
|
||||
|
||||
## React
|
||||
|
||||
The Virtual Scroll component is not supported in React.
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
||||
@ -240,76 +243,6 @@ within a `<div>` is a safe way to make sure dimensions are measured correctly.
|
||||
```
|
||||
|
||||
|
||||
### React
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
|
||||
import { IonContent, IonCard, IonCardHeader, IonCardTitle, IonVirtualScroll } from '@ionic/react';
|
||||
|
||||
let rotateImg = 0;
|
||||
const lorem = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, seddo eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
|
||||
|
||||
const images = [
|
||||
'bandit',
|
||||
'batmobile',
|
||||
'blues-brothers',
|
||||
'bueller',
|
||||
'delorean',
|
||||
'eleanor',
|
||||
'general-lee',
|
||||
'ghostbusters',
|
||||
'knight-rider',
|
||||
'mirth-mobile'
|
||||
];
|
||||
|
||||
function getImgSrc() {
|
||||
const src = 'https://dummyimage.com/600x400/${Math.round( Math.random() * 99999)}/fff.png';
|
||||
rotateImg++;
|
||||
if (rotateImg === images.length) {
|
||||
rotateImg = 0;
|
||||
}
|
||||
return src;
|
||||
}
|
||||
|
||||
const items: any[] = [];
|
||||
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
items.push({
|
||||
name: i + ' - ' + images[rotateImg],
|
||||
imgSrc: getImgSrc(),
|
||||
avatarSrc: getImgSrc(),
|
||||
imgHeight: Math.floor(Math.random() * 50 + 150),
|
||||
content: lorem.substring(0, Math.random() * (lorem.length - 100) + 100)
|
||||
});
|
||||
|
||||
rotateImg++;
|
||||
if (rotateImg === images.length) {
|
||||
rotateImg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const Example: React.SFC<{}> = () => (
|
||||
|
||||
<IonContent>
|
||||
<IonVirtualScroll items="items" approxItemHeight="320px">
|
||||
<IonCard virtualItem="let item; let itemBounds = bounds;">
|
||||
<div>
|
||||
<img src="item.imgSrc" height="item.imgHeight" alt="item.name" />
|
||||
</div>
|
||||
<IonCardHeader>
|
||||
<IonCardTitle>{{ name }}</IonCardTitle>
|
||||
</IonCardHeader>
|
||||
<IonCardContent>{{ content }}</IonCardContent>
|
||||
</IonCard>
|
||||
</IonVirtualScroll>
|
||||
</IonContent>
|
||||
);
|
||||
|
||||
export default Example;
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
@ -330,37 +263,32 @@ export default Example;
|
||||
|
||||
## Methods
|
||||
|
||||
### `checkEnd() => void`
|
||||
### `checkEnd() => Promise<void>`
|
||||
|
||||
Marks the tail of the items array as dirty, so they can be re-rendered.
|
||||
It's equivalent to calling `checkRange(length)` where `length` is the
|
||||
total length of the items.
|
||||
This method marks the tail the items array as dirty, so they can be re-rendered.
|
||||
|
||||
It's equivalent to calling:
|
||||
|
||||
```js
|
||||
virtualScroll.checkRange(lastItemLen);
|
||||
```
|
||||
|
||||
#### Returns
|
||||
|
||||
Type: `void`
|
||||
Type: `Promise<void>`
|
||||
|
||||
|
||||
|
||||
### `checkRange(offset: number, length?: number) => void`
|
||||
### `checkRange(offset: number, len?: number) => Promise<void>`
|
||||
|
||||
Marks a subset of the items as dirty so they can be re-rendered.
|
||||
Items should be marked as dirty any time the content or their style changes.
|
||||
This method marks a subset of items as dirty, so they can be re-rendered. Items should be marked as
|
||||
dirty any time the content or their style changes.
|
||||
|
||||
The subset of items to be updated are specified by an offset and a length.
|
||||
If a length is not provided it will check all of the items beginning at
|
||||
the offset.
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| -------- | -------- | --------------------------------------------- |
|
||||
| `offset` | `number` | The index of the item to start marking dirty. |
|
||||
| `length` | `number` | The number of items to mark dirty. |
|
||||
The subset of items to be updated can are specifing by an offset and a length.
|
||||
|
||||
#### Returns
|
||||
|
||||
Type: `void`
|
||||
Type: `Promise<void>`
|
||||
|
||||
|
||||
|
||||
@ -368,12 +296,6 @@ Type: `void`
|
||||
|
||||
Returns the position of the virtual item at the given index.
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------- | -------- | ---------------------- |
|
||||
| `index` | `number` | The index of the item. |
|
||||
|
||||
#### Returns
|
||||
|
||||
Type: `Promise<number>`
|
||||
|
@ -8,8 +8,8 @@
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet">
|
||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
|
||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||
<script src="../../../../../dist/ionic.js"></script>
|
||||
</head>
|
||||
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script></head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
|
@ -8,8 +8,8 @@
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet">
|
||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
|
||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||
<script src="../../../../../dist/ionic.js"></script>
|
||||
</head>
|
||||
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script></head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
|
@ -1,66 +0,0 @@
|
||||
```tsx
|
||||
import React from 'react';
|
||||
|
||||
import { IonContent, IonCard, IonCardHeader, IonCardTitle, IonVirtualScroll } from '@ionic/react';
|
||||
|
||||
let rotateImg = 0;
|
||||
const lorem = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, seddo eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
|
||||
|
||||
const images = [
|
||||
'bandit',
|
||||
'batmobile',
|
||||
'blues-brothers',
|
||||
'bueller',
|
||||
'delorean',
|
||||
'eleanor',
|
||||
'general-lee',
|
||||
'ghostbusters',
|
||||
'knight-rider',
|
||||
'mirth-mobile'
|
||||
];
|
||||
|
||||
function getImgSrc() {
|
||||
const src = 'https://dummyimage.com/600x400/${Math.round( Math.random() * 99999)}/fff.png';
|
||||
rotateImg++;
|
||||
if (rotateImg === images.length) {
|
||||
rotateImg = 0;
|
||||
}
|
||||
return src;
|
||||
}
|
||||
|
||||
const items: any[] = [];
|
||||
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
items.push({
|
||||
name: i + ' - ' + images[rotateImg],
|
||||
imgSrc: getImgSrc(),
|
||||
avatarSrc: getImgSrc(),
|
||||
imgHeight: Math.floor(Math.random() * 50 + 150),
|
||||
content: lorem.substring(0, Math.random() * (lorem.length - 100) + 100)
|
||||
});
|
||||
|
||||
rotateImg++;
|
||||
if (rotateImg === images.length) {
|
||||
rotateImg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const Example: React.SFC<{}> = () => (
|
||||
|
||||
<IonContent>
|
||||
<IonVirtualScroll items="items" approxItemHeight="320px">
|
||||
<IonCard virtualItem="let item; let itemBounds = bounds;">
|
||||
<div>
|
||||
<img src="item.imgSrc" height="item.imgHeight" alt="item.name" />
|
||||
</div>
|
||||
<IonCardHeader>
|
||||
<IonCardTitle>{{ name }}</IonCardTitle>
|
||||
</IonCardHeader>
|
||||
<IonCardContent>{{ content }}</IonCardContent>
|
||||
</IonCard>
|
||||
</IonVirtualScroll>
|
||||
</IonContent>
|
||||
);
|
||||
|
||||
export default Example;
|
||||
```
|
@ -1,4 +1,4 @@
|
||||
import { Component, ComponentInterface, Element, EventListenerEnable, FunctionalComponent, Listen, Method, Prop, QueueApi, State, Watch } from '@stencil/core';
|
||||
import { Component, ComponentInterface, Element, FunctionalComponent, Listen, Method, Prop, State, Watch, h, readTask, writeTask } from '@stencil/core';
|
||||
|
||||
import { Cell, DomRenderFn, HeaderFn, ItemHeightFn, ItemRenderFn, VirtualNode } from '../../interface';
|
||||
|
||||
@ -24,15 +24,12 @@ export class VirtualScroll implements ComponentInterface {
|
||||
private currentScrollTop = 0;
|
||||
private indexDirty = 0;
|
||||
private lastItemLen = 0;
|
||||
private rmEvent: (() => void) | undefined;
|
||||
|
||||
@Element() el!: HTMLStencilElement;
|
||||
@Element() el!: HTMLIonVirtualScrollElement;
|
||||
|
||||
@State() totalHeight = 0;
|
||||
|
||||
@Prop({ context: 'queue' }) queue!: QueueApi;
|
||||
@Prop({ context: 'enableListener' }) enableListener!: EventListenerEnable;
|
||||
@Prop({ context: 'window' }) win!: Window;
|
||||
|
||||
/**
|
||||
* It is important to provide this
|
||||
* if virtual item height will be significantly larger than the default
|
||||
@ -165,20 +162,13 @@ export class VirtualScroll implements ComponentInterface {
|
||||
this.scrollEl = undefined;
|
||||
}
|
||||
|
||||
@Listen('scroll', { enabled: false, passive: false })
|
||||
onScroll() {
|
||||
this.updateVirtualScroll();
|
||||
}
|
||||
|
||||
@Listen('window:resize')
|
||||
@Listen('resize', { target: 'window' })
|
||||
onResize() {
|
||||
this.updateVirtualScroll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of the virtual item at the given index.
|
||||
*
|
||||
* @param index The index of the item.
|
||||
*/
|
||||
@Method()
|
||||
positionForItem(index: number): Promise<number> {
|
||||
@ -186,26 +176,21 @@ export class VirtualScroll implements ComponentInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks a subset of the items as dirty so they can be re-rendered.
|
||||
* Items should be marked as dirty any time the content or their style changes.
|
||||
* This method marks a subset of items as dirty, so they can be re-rendered. Items should be marked as
|
||||
* dirty any time the content or their style changes.
|
||||
*
|
||||
* The subset of items to be updated are specified by an offset and a length.
|
||||
* If a length is not provided it will check all of the items beginning at
|
||||
* the offset.
|
||||
*
|
||||
* @param offset The index of the item to start marking dirty.
|
||||
* @param length The number of items to mark dirty.
|
||||
* The subset of items to be updated can are specifing by an offset and a length.
|
||||
*/
|
||||
@Method()
|
||||
checkRange(offset: number, length = -1) {
|
||||
async checkRange(offset: number, len = -1) {
|
||||
// TODO: kind of hacky how we do in-place updated of the cells
|
||||
// array. this part needs a complete refactor
|
||||
if (!this.items) {
|
||||
return;
|
||||
}
|
||||
const len = (length === -1)
|
||||
const length = (len === -1)
|
||||
? this.items.length - offset
|
||||
: length;
|
||||
: len;
|
||||
|
||||
const cellIndex = findCellIndex(this.cells, offset);
|
||||
const cells = calcCells(
|
||||
@ -216,7 +201,7 @@ export class VirtualScroll implements ComponentInterface {
|
||||
this.approxHeaderHeight,
|
||||
this.approxFooterHeight,
|
||||
this.approxItemHeight,
|
||||
cellIndex, offset, len
|
||||
cellIndex, offset, length
|
||||
);
|
||||
this.cells = inplaceUpdate(this.cells, cells, cellIndex);
|
||||
this.lastItemLen = this.items.length;
|
||||
@ -226,17 +211,25 @@ export class VirtualScroll implements ComponentInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the tail of the items array as dirty, so they can be re-rendered.
|
||||
* It's equivalent to calling `checkRange(length)` where `length` is the
|
||||
* total length of the items.
|
||||
* This method marks the tail the items array as dirty, so they can be re-rendered.
|
||||
*
|
||||
* It's equivalent to calling:
|
||||
*
|
||||
* ```js
|
||||
* virtualScroll.checkRange(lastItemLen);
|
||||
* ```
|
||||
*/
|
||||
@Method()
|
||||
checkEnd() {
|
||||
async checkEnd() {
|
||||
if (this.items) {
|
||||
this.checkRange(this.lastItemLen);
|
||||
}
|
||||
}
|
||||
|
||||
private onScroll = () => {
|
||||
this.updateVirtualScroll();
|
||||
}
|
||||
|
||||
private updateVirtualScroll() {
|
||||
// do nothing if virtual-scroll is disabled
|
||||
if (!this.isEnabled || !this.scrollEl) {
|
||||
@ -250,8 +243,8 @@ export class VirtualScroll implements ComponentInterface {
|
||||
}
|
||||
|
||||
// schedule DOM operations into the stencil queue
|
||||
this.queue.read(this.readVS.bind(this));
|
||||
this.queue.write(this.writeVS.bind(this));
|
||||
readTask(this.readVS.bind(this));
|
||||
writeTask(this.writeVS.bind(this));
|
||||
}
|
||||
|
||||
private readVS() {
|
||||
@ -311,7 +304,7 @@ export class VirtualScroll implements ComponentInterface {
|
||||
private updateCellHeight(cell: Cell, node: any) {
|
||||
const update = () => {
|
||||
if ((node as any)['$ionCell'] === cell) {
|
||||
const style = this.win.getComputedStyle(node);
|
||||
const style = window.getComputedStyle(node);
|
||||
const height = node.offsetHeight + parseFloat(style.getPropertyValue('margin-bottom'));
|
||||
this.setCellHeight(cell, height);
|
||||
}
|
||||
@ -389,9 +382,18 @@ export class VirtualScroll implements ComponentInterface {
|
||||
}
|
||||
|
||||
private enableScrollEvents(shouldListen: boolean) {
|
||||
if (this.scrollEl) {
|
||||
if (this.rmEvent) {
|
||||
this.rmEvent();
|
||||
this.rmEvent = undefined;
|
||||
}
|
||||
|
||||
const scrollEl = this.scrollEl;
|
||||
if (scrollEl) {
|
||||
this.isEnabled = shouldListen;
|
||||
this.enableListener(this, 'scroll', shouldListen, this.scrollEl);
|
||||
scrollEl.addEventListener('scroll', this.onScroll);
|
||||
this.rmEvent = () => {
|
||||
scrollEl.removeEventListener('scroll', this.onScroll);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user