mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-23 05:58:26 +08:00
perf(virtual-scroll): scroll events
This commit is contained in:
5
packages/core/src/components.d.ts
vendored
5
packages/core/src/components.d.ts
vendored
@ -759,9 +759,6 @@ declare global {
|
|||||||
namespace JSXElements {
|
namespace JSXElements {
|
||||||
export interface IonContentAttributes extends HTMLAttributes {
|
export interface IonContentAttributes extends HTMLAttributes {
|
||||||
fullscreen?: boolean;
|
fullscreen?: boolean;
|
||||||
ionScroll?: Function;
|
|
||||||
ionScrollEnd?: Function;
|
|
||||||
ionScrollStart?: Function;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2530,10 +2527,10 @@ declare global {
|
|||||||
}
|
}
|
||||||
namespace JSXElements {
|
namespace JSXElements {
|
||||||
export interface IonScrollAttributes extends HTMLAttributes {
|
export interface IonScrollAttributes extends HTMLAttributes {
|
||||||
disabled?: boolean;
|
|
||||||
onionScroll?: ScrollCallback;
|
onionScroll?: ScrollCallback;
|
||||||
onionScrollEnd?: ScrollCallback;
|
onionScrollEnd?: ScrollCallback;
|
||||||
onionScrollStart?: ScrollCallback;
|
onionScrollStart?: ScrollCallback;
|
||||||
|
scrollEvents?: boolean;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,21 +25,6 @@ export class Content {
|
|||||||
@Prop({ context: 'config' }) config: Config;
|
@Prop({ context: 'config' }) config: Config;
|
||||||
@Prop({ context: 'dom' }) dom: DomController;
|
@Prop({ context: 'dom' }) dom: DomController;
|
||||||
|
|
||||||
/**
|
|
||||||
* Emitted when the scrolling first starts.
|
|
||||||
*/
|
|
||||||
@Prop() ionScrollStart: Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emitted on every scroll event.
|
|
||||||
*/
|
|
||||||
@Prop() ionScroll: Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emitted when scrolling ends.
|
|
||||||
*/
|
|
||||||
@Prop() ionScrollEnd: Function;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If true, the content will scroll behind the headers
|
* If true, the content will scroll behind the headers
|
||||||
* and footers. This effect can easily be seen by setting the toolbar
|
* and footers. This effect can easily be seen by setting the toolbar
|
||||||
|
@ -25,27 +25,6 @@ and footers. This effect can easily be seen by setting the toolbar
|
|||||||
to transparent.
|
to transparent.
|
||||||
|
|
||||||
|
|
||||||
#### ionScroll
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Emitted on every scroll event.
|
|
||||||
|
|
||||||
|
|
||||||
#### ionScrollEnd
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Emitted when scrolling ends.
|
|
||||||
|
|
||||||
|
|
||||||
#### ionScrollStart
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Emitted when the scrolling first starts.
|
|
||||||
|
|
||||||
|
|
||||||
## Attributes
|
## Attributes
|
||||||
|
|
||||||
#### fullscreen
|
#### fullscreen
|
||||||
@ -57,27 +36,6 @@ and footers. This effect can easily be seen by setting the toolbar
|
|||||||
to transparent.
|
to transparent.
|
||||||
|
|
||||||
|
|
||||||
#### ion-scroll
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Emitted on every scroll event.
|
|
||||||
|
|
||||||
|
|
||||||
#### ion-scroll-end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Emitted when scrolling ends.
|
|
||||||
|
|
||||||
|
|
||||||
#### ion-scroll-start
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Emitted when the scrolling first starts.
|
|
||||||
|
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
#### scrollToBottom()
|
#### scrollToBottom()
|
||||||
|
@ -227,6 +227,9 @@ export class InfiniteScroll {
|
|||||||
|
|
||||||
private enableScrollEvents(shouldListen: boolean) {
|
private enableScrollEvents(shouldListen: boolean) {
|
||||||
if (this.scrollEl) {
|
if (this.scrollEl) {
|
||||||
|
if (shouldListen) {
|
||||||
|
this.scrollEl.scrollEvents = true;
|
||||||
|
}
|
||||||
this.enableListener(this, 'ionScroll', shouldListen, this.scrollEl);
|
this.enableListener(this, 'ionScroll', shouldListen, this.scrollEl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core';
|
import { Component, Element, Event, EventEmitter, EventListenerEnable, Listen, Method, Prop, Watch } from '@stencil/core';
|
||||||
import { Config, DomController, GestureDetail } from '../../index';
|
import { Config, DomController, GestureDetail } from '../../index';
|
||||||
import { GestureController, GestureDelegate } from '../gesture-controller/gesture-controller';
|
import { GestureController, GestureDelegate } from '../gesture-controller/gesture-controller';
|
||||||
|
|
||||||
@ -21,11 +21,10 @@ export class Scroll {
|
|||||||
@Element() private el: HTMLElement;
|
@Element() private el: HTMLElement;
|
||||||
|
|
||||||
@Prop({ context: 'config'}) config: Config;
|
@Prop({ context: 'config'}) config: Config;
|
||||||
|
@Prop({ context: 'enableListener'}) enableListener: EventListenerEnable;
|
||||||
@Prop({ context: 'dom' }) dom: DomController;
|
@Prop({ context: 'dom' }) dom: DomController;
|
||||||
@Prop({ context: 'isServer' }) isServer: boolean;
|
@Prop({ context: 'isServer' }) isServer: boolean;
|
||||||
|
|
||||||
@Prop() disabled = false;
|
|
||||||
|
|
||||||
@Prop() onionScrollStart: ScrollCallback;
|
@Prop() onionScrollStart: ScrollCallback;
|
||||||
@Prop() onionScroll: ScrollCallback;
|
@Prop() onionScroll: ScrollCallback;
|
||||||
@Prop() onionScrollEnd: ScrollCallback;
|
@Prop() onionScrollEnd: ScrollCallback;
|
||||||
@ -45,6 +44,13 @@ export class Scroll {
|
|||||||
*/
|
*/
|
||||||
@Event() ionScrollEnd: EventEmitter;
|
@Event() ionScrollEnd: EventEmitter;
|
||||||
|
|
||||||
|
|
||||||
|
@Prop() scrollEvents = false;
|
||||||
|
@Watch('scrollEvents')
|
||||||
|
scrollChanged(enabled: boolean) {
|
||||||
|
this.enableListener(this, 'scroll', enabled);
|
||||||
|
}
|
||||||
|
|
||||||
componentDidLoad() {
|
componentDidLoad() {
|
||||||
if (this.isServer) {
|
if (this.isServer) {
|
||||||
return;
|
return;
|
||||||
@ -53,6 +59,7 @@ export class Scroll {
|
|||||||
const gestureCtrl = Ionic.gesture = Ionic.gesture || new GestureController();
|
const gestureCtrl = Ionic.gesture = Ionic.gesture || new GestureController();
|
||||||
this.gesture = gestureCtrl.createGesture('scroll', 100, false);
|
this.gesture = gestureCtrl.createGesture('scroll', 100, false);
|
||||||
this.app = this.el.closest('ion-app') as HTMLIonAppElement;
|
this.app = this.el.closest('ion-app') as HTMLIonAppElement;
|
||||||
|
this.scrollChanged(this.scrollEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUnload() {
|
componentDidUnload() {
|
||||||
@ -62,7 +69,7 @@ export class Scroll {
|
|||||||
|
|
||||||
// Native Scroll *************************
|
// Native Scroll *************************
|
||||||
|
|
||||||
@Listen('scroll', { passive: true })
|
@Listen('scroll', { passive: true, enabled: false })
|
||||||
onNativeScroll() {
|
onNativeScroll() {
|
||||||
if (!this.queued) {
|
if (!this.queued) {
|
||||||
this.queued = true;
|
this.queued = true;
|
||||||
|
@ -21,10 +21,10 @@ export const enum NodeChange {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Cell {
|
export interface Cell {
|
||||||
type: CellType;
|
|
||||||
value: any;
|
|
||||||
i: number;
|
i: number;
|
||||||
index: number;
|
index: number;
|
||||||
|
value: any;
|
||||||
|
type: CellType;
|
||||||
height: number;
|
height: number;
|
||||||
reads: number;
|
reads: number;
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@ -35,6 +35,7 @@ export interface VirtualNode {
|
|||||||
top: number;
|
top: number;
|
||||||
change: NodeChange;
|
change: NodeChange;
|
||||||
d: boolean;
|
d: boolean;
|
||||||
|
visible: boolean;
|
||||||
}
|
}
|
||||||
const MIN_READS = 2;
|
const MIN_READS = 2;
|
||||||
|
|
||||||
@ -88,6 +89,7 @@ export function updateVDom(dom: VirtualNode[], heightIndex: Uint32Array, cells:
|
|||||||
dom.push({
|
dom.push({
|
||||||
d: false,
|
d: false,
|
||||||
cell: cell,
|
cell: cell,
|
||||||
|
visible: true,
|
||||||
change: NodeChange.Cell,
|
change: NodeChange.Cell,
|
||||||
top: heightIndex[index],
|
top: heightIndex[index],
|
||||||
});
|
});
|
||||||
@ -106,8 +108,10 @@ export function doRender(
|
|||||||
el: HTMLElement,
|
el: HTMLElement,
|
||||||
itemRender: ItemRenderFn,
|
itemRender: ItemRenderFn,
|
||||||
dom: VirtualNode[],
|
dom: VirtualNode[],
|
||||||
updateCellHeight: Function) {
|
updateCellHeight: Function
|
||||||
|
) {
|
||||||
const children = el.children;
|
const children = el.children;
|
||||||
|
const childrenNu = children.length;
|
||||||
let child: HTMLElement;
|
let child: HTMLElement;
|
||||||
for (let i = 0; i < dom.length; i++) {
|
for (let i = 0; i < dom.length; i++) {
|
||||||
const node = dom[i];
|
const node = dom[i];
|
||||||
@ -115,7 +119,7 @@ export function doRender(
|
|||||||
|
|
||||||
// the cell change, the content must be updated
|
// the cell change, the content must be updated
|
||||||
if (node.change === NodeChange.Cell) {
|
if (node.change === NodeChange.Cell) {
|
||||||
if (i < children.length) {
|
if (i < childrenNu) {
|
||||||
child = children[i] as HTMLElement;
|
child = children[i] as HTMLElement;
|
||||||
itemRender(child, cell, i);
|
itemRender(child, cell, i);
|
||||||
} else {
|
} else {
|
||||||
@ -132,13 +136,22 @@ export function doRender(
|
|||||||
if (node.change !== NodeChange.NoChange) {
|
if (node.change !== NodeChange.NoChange) {
|
||||||
child.style.transform = `translate3d(0,${node.top}px,0)`;
|
child.style.transform = `translate3d(0,${node.top}px,0)`;
|
||||||
}
|
}
|
||||||
if (cell.visible) {
|
|
||||||
|
// update visibility
|
||||||
|
const visible = cell.visible;
|
||||||
|
if (node.visible !== visible) {
|
||||||
|
if (visible) {
|
||||||
child.classList.remove('virtual-loading');
|
child.classList.remove('virtual-loading');
|
||||||
} else {
|
} else {
|
||||||
child.classList.add('virtual-loading');
|
child.classList.add('virtual-loading');
|
||||||
}
|
}
|
||||||
|
node.visible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dynamic height inference
|
||||||
if (cell.reads > 0) {
|
if (cell.reads > 0) {
|
||||||
updateCellHeight(cell, child);
|
updateCellHeight(cell, child);
|
||||||
|
cell.reads--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,7 +228,6 @@ export class VirtualScroll {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cell.visible = true;
|
cell.visible = true;
|
||||||
cell.reads--;
|
|
||||||
if (cell.height !== height) {
|
if (cell.height !== height) {
|
||||||
console.debug(`[${cell.reads}] cell size ${cell.height} -> ${height}`);
|
console.debug(`[${cell.reads}] cell size ${cell.height} -> ${height}`);
|
||||||
cell.height = height;
|
cell.height = height;
|
||||||
|
Reference in New Issue
Block a user