mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 03:32:21 +08:00
fix(virtual-scroll): fixes dynamic changes
This commit is contained in:
@ -256,8 +256,8 @@ let rotateImg = 0;
|
||||
|
||||
| Property | Attribute | Description | Type | Default |
|
||||
| -------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------- | ----------- |
|
||||
| `approxFooterHeight` | `approx-footer-height` | The approximate width of each footer template's cell. This dimension is used to help determine how many cells should be created when initialized, and to help calculate the height of the scrollable area. This value can use either `px` or `%` units. Note that the actual rendered size of each cell comes from the app's CSS, whereas this approximation is used to help calculate initial dimensions before the item has been rendered. | `number` | `40` |
|
||||
| `approxHeaderHeight` | `approx-header-height` | The approximate height of each header template's cell. This dimension is used to help determine how many cells should be created when initialized, and to help calculate the height of the scrollable area. This height value can only use `px` units. Note that the actual rendered size of each cell comes from the app's CSS, whereas this approximation is used to help calculate initial dimensions before the item has been rendered. | `number` | `40` |
|
||||
| `approxFooterHeight` | `approx-footer-height` | The approximate width of each footer template's cell. This dimension is used to help determine how many cells should be created when initialized, and to help calculate the height of the scrollable area. This height value can only use `px` units. Note that the actual rendered size of each cell comes from the app's CSS, whereas this approximation is used to help calculate initial dimensions before the item has been rendered. | `number` | `30` |
|
||||
| `approxHeaderHeight` | `approx-header-height` | The approximate height of each header template's cell. This dimension is used to help determine how many cells should be created when initialized, and to help calculate the height of the scrollable area. This height value can only use `px` units. Note that the actual rendered size of each cell comes from the app's CSS, whereas this approximation is used to help calculate initial dimensions before the item has been rendered. | `number` | `30` |
|
||||
| `approxItemHeight` | `approx-item-height` | It is important to provide this if virtual item height will be significantly larger than the default The approximate height of each virtual item template's cell. This dimension is used to help determine how many cells should be created when initialized, and to help calculate the height of the scrollable area. This height value can only use `px` units. Note that the actual rendered size of each cell comes from the app's CSS, whereas this approximation is used to help calculate initial dimensions before the item has been rendered. | `number` | `45` |
|
||||
| `footerFn` | -- | Section footers and the data used within its given template can be dynamically created by passing a function to `footerFn`. The logic within the footer function can decide if the footer template should be used, and what data to give to the footer template. The function must return `null` if a footer cell shouldn't be created. | `((item: any, index: number, items: any[]) => string \| null \| undefined) \| undefined` | `undefined` |
|
||||
| `headerFn` | -- | Section headers and the data used within its given template can be dynamically created by passing a function to `headerFn`. For example, a large list of contacts usually has dividers between each letter in the alphabet. App's can provide their own custom `headerFn` which is called with each record within the dataset. The logic within the header function can decide if the header template should be used, and what data to give to the header template. The function must return `null` if a header cell shouldn't be created. | `((item: any, index: number, items: any[]) => string \| null \| undefined) \| undefined` | `undefined` |
|
||||
@ -271,7 +271,23 @@ let rotateImg = 0;
|
||||
|
||||
## Methods
|
||||
|
||||
### `markDirty(offset: number, len?: number) => void`
|
||||
### `checkEnd() => void`
|
||||
|
||||
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`
|
||||
|
||||
|
||||
|
||||
### `checkRange(offset: number, len?: number) => void`
|
||||
|
||||
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.
|
||||
@ -291,22 +307,6 @@ Type: `void`
|
||||
|
||||
|
||||
|
||||
### `markDirtyTail() => void`
|
||||
|
||||
This method marks the tail the items array as dirty, so they can be re-rendered.
|
||||
|
||||
It's equivalent to calling:
|
||||
|
||||
```
|
||||
* virtualScroll.markDirty(lastItemLen, items.length - lastItemLen);
|
||||
* ```
|
||||
|
||||
#### Returns
|
||||
|
||||
Type: `void`
|
||||
|
||||
|
||||
|
||||
### `positionForItem(index: number) => Promise<number>`
|
||||
|
||||
Returns the position of the virtual item at the given index.
|
||||
|
@ -51,10 +51,9 @@
|
||||
<script>
|
||||
const items = Array.from({ length: 100 }, (x, i) => i);
|
||||
const virtual = document.getElementById('virtual');
|
||||
virtual.itemHeight = () => 44;
|
||||
virtual.items = items;
|
||||
virtual.nodeRender = (el, cell) => {
|
||||
if (cell.type === 0) {
|
||||
if (cell.type === 'item') {
|
||||
renderItem(el, cell.value);
|
||||
}
|
||||
};
|
||||
@ -75,7 +74,7 @@
|
||||
append = Array.from({ length: 10 }, (x, i) => "append" + i);
|
||||
}
|
||||
items.push(...append);
|
||||
virtual.markDirtyTail(append.length)
|
||||
virtual.checkEnd(append.length);
|
||||
}
|
||||
|
||||
function getAsyncData() {
|
||||
|
@ -181,10 +181,14 @@ export function getShouldUpdate(dirtyIndex: number, currentRange: Range, range:
|
||||
}
|
||||
|
||||
export function findCellIndex(cells: Cell[], index: number): number {
|
||||
const max = cells[cells.length - 1].index || 0;
|
||||
if (index === 0) {
|
||||
return 0;
|
||||
} else if (index === max + 1) {
|
||||
return cells.length;
|
||||
} else {
|
||||
return cells.findIndex(c => c.index === index);
|
||||
}
|
||||
return cells.findIndex(c => c.index === index);
|
||||
}
|
||||
|
||||
export function inplaceUpdate(dst: Cell[], src: Cell[], offset: number) {
|
||||
|
@ -55,18 +55,18 @@ export class VirtualScroll implements ComponentInterface {
|
||||
* app's CSS, whereas this approximation is used to help calculate
|
||||
* initial dimensions before the item has been rendered.
|
||||
*/
|
||||
@Prop() approxHeaderHeight = 40;
|
||||
@Prop() approxHeaderHeight = 30;
|
||||
|
||||
/**
|
||||
* The approximate width of each footer template's cell.
|
||||
* This dimension is used to help determine how many cells should
|
||||
* be created when initialized, and to help calculate the height of
|
||||
* the scrollable area. This value can use either `px` or `%` units.
|
||||
* the scrollable area. This height value can only use `px` units.
|
||||
* Note that the actual rendered size of each cell comes from the
|
||||
* app's CSS, whereas this approximation is used to help calculate
|
||||
* initial dimensions before the item has been rendered.
|
||||
*/
|
||||
@Prop() approxFooterHeight = 40;
|
||||
@Prop() approxFooterHeight = 30;
|
||||
|
||||
/**
|
||||
* Section headers and the data used within its given
|
||||
@ -190,7 +190,7 @@ export class VirtualScroll implements ComponentInterface {
|
||||
* The subset of items to be updated can are specifing by an offset and a length.
|
||||
*/
|
||||
@Method()
|
||||
markDirty(offset: number, len = -1) {
|
||||
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) {
|
||||
@ -200,18 +200,7 @@ export class VirtualScroll implements ComponentInterface {
|
||||
? this.items.length - offset
|
||||
: len;
|
||||
|
||||
const max = this.lastItemLen;
|
||||
let j = 0;
|
||||
if (offset > 0 && offset < max) {
|
||||
j = findCellIndex(this.cells, offset);
|
||||
} else if (offset === 0) {
|
||||
j = 0;
|
||||
} else if (offset === max) {
|
||||
j = this.cells.length;
|
||||
} else {
|
||||
console.warn('bad values for markDirty');
|
||||
return;
|
||||
}
|
||||
const cellIndex = findCellIndex(this.cells, offset);
|
||||
const cells = calcCells(
|
||||
this.items,
|
||||
this.itemHeight,
|
||||
@ -220,10 +209,10 @@ export class VirtualScroll implements ComponentInterface {
|
||||
this.approxHeaderHeight,
|
||||
this.approxFooterHeight,
|
||||
this.approxItemHeight,
|
||||
j, offset, length
|
||||
cellIndex, offset, length
|
||||
);
|
||||
console.debug('[virtual] cells recalculated', cells.length);
|
||||
this.cells = inplaceUpdate(this.cells, cells, offset);
|
||||
this.cells = inplaceUpdate(this.cells, cells, cellIndex);
|
||||
this.lastItemLen = this.items.length;
|
||||
this.indexDirty = Math.max(offset - 1, 0);
|
||||
|
||||
@ -235,15 +224,14 @@ export class VirtualScroll implements ComponentInterface {
|
||||
*
|
||||
* It's equivalent to calling:
|
||||
*
|
||||
* ```
|
||||
* virtualScroll.markDirty(lastItemLen, items.length - lastItemLen);
|
||||
* ```js
|
||||
* virtualScroll.checkRange(lastItemLen);
|
||||
* ```
|
||||
*/
|
||||
@Method()
|
||||
markDirtyTail() {
|
||||
checkEnd() {
|
||||
if (this.items) {
|
||||
const offset = this.lastItemLen;
|
||||
this.markDirty(offset, this.items.length - offset);
|
||||
this.checkRange(this.lastItemLen);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user