mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-21 04:53:58 +08:00
fix(scroll): simplify scroll
This commit is contained in:
@ -272,10 +272,8 @@ export class Gesture {
|
|||||||
let startPos = positions.length - 1;
|
let startPos = positions.length - 1;
|
||||||
|
|
||||||
// move pointer to position measured 100ms ago
|
// move pointer to position measured 100ms ago
|
||||||
for (;
|
while (startPos > 0 && positions[startPos] > timeRange) {
|
||||||
startPos > 0 && positions[startPos] > timeRange;
|
startPos -= 3;
|
||||||
startPos -= 3) {
|
|
||||||
// TODO why is this empty?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startPos > 1) {
|
if (startPos > 1) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, Element, Event, EventEmitter, Listen, Method, Prop, State, Watch } from '@stencil/core';
|
import { Component, Element, Event, EventEmitter, EventListenerEnable, Listen, Method, Prop, State, Watch } from '@stencil/core';
|
||||||
import { DomController, ScrollDetail, StencilElement } from '../../index';
|
import { DomController, ScrollDetail, StencilElement } from '../../index';
|
||||||
|
|
||||||
const enum Position {
|
const enum Position {
|
||||||
@ -14,7 +14,7 @@ const enum Position {
|
|||||||
export class InfiniteScroll {
|
export class InfiniteScroll {
|
||||||
|
|
||||||
private thrPx = 0;
|
private thrPx = 0;
|
||||||
private thrPc = 0.15;
|
private thrPc = 0;
|
||||||
private scrollEl: HTMLIonScrollElement;
|
private scrollEl: HTMLIonScrollElement;
|
||||||
private didFire = false;
|
private didFire = false;
|
||||||
private isBusy = false;
|
private isBusy = false;
|
||||||
@ -24,7 +24,7 @@ export class InfiniteScroll {
|
|||||||
@State() isLoading = false;
|
@State() isLoading = false;
|
||||||
|
|
||||||
@Prop({ context: 'dom' }) dom: DomController;
|
@Prop({ context: 'dom' }) dom: DomController;
|
||||||
@Prop({ context: 'enableListener' }) enableListener: any;
|
@Prop({ context: 'enableListener' }) enableListener: EventListenerEnable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @input {string} The threshold distance from the bottom
|
* @input {string} The threshold distance from the bottom
|
||||||
@ -142,14 +142,6 @@ export class InfiniteScroll {
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
private canStart(): boolean {
|
|
||||||
return (
|
|
||||||
!this.disabled &&
|
|
||||||
!this.isBusy &&
|
|
||||||
this.scrollEl &&
|
|
||||||
!this.isLoading);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call `complete()` within the `infinite` output event handler when
|
* Call `complete()` within the `infinite` output event handler when
|
||||||
* your async operation has completed. For example, the `loading`
|
* your async operation has completed. For example, the `loading`
|
||||||
@ -212,11 +204,20 @@ export class InfiniteScroll {
|
|||||||
* Pass a promise inside `waitFor()` within the `infinite` output event handler in order to
|
* Pass a promise inside `waitFor()` within the `infinite` output event handler in order to
|
||||||
* change state of infiniteScroll to "complete"
|
* change state of infiniteScroll to "complete"
|
||||||
*/
|
*/
|
||||||
|
@Method()
|
||||||
waitFor(action: Promise<any>) {
|
waitFor(action: Promise<any>) {
|
||||||
const enable = this.complete.bind(this);
|
const enable = this.complete.bind(this);
|
||||||
action.then(enable, enable);
|
action.then(enable, enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private canStart(): boolean {
|
||||||
|
return (
|
||||||
|
!this.disabled &&
|
||||||
|
!this.isBusy &&
|
||||||
|
this.scrollEl &&
|
||||||
|
!this.isLoading);
|
||||||
|
}
|
||||||
|
|
||||||
private enableScrollEvents(shouldListen: boolean) {
|
private enableScrollEvents(shouldListen: boolean) {
|
||||||
this.enableListener(this, 'ionScroll', shouldListen, this.scrollEl);
|
this.enableListener(this, 'ionScroll', shouldListen, this.scrollEl);
|
||||||
}
|
}
|
||||||
|
@ -66,8 +66,20 @@ export class Modal {
|
|||||||
@Prop({ context: 'config' }) config: Config;
|
@Prop({ context: 'config' }) config: Config;
|
||||||
@Prop({ context: 'dom' }) dom: DomController;
|
@Prop({ context: 'dom' }) dom: DomController;
|
||||||
|
|
||||||
@Prop() mode: string;
|
/**
|
||||||
|
* @input {string} The color to use from your Sass `$colors` map.
|
||||||
|
* Default options are: `"primary"`, `"secondary"`, `"danger"`, `"light"`, and `"dark"`.
|
||||||
|
* For more information, see [Theming your App](/docs/theming/theming-your-app).
|
||||||
|
*/
|
||||||
@Prop() color: string;
|
@Prop() color: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @input {string} The mode determines which platform styles to use.
|
||||||
|
* Possible values are: `"ios"` or `"md"`.
|
||||||
|
* For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
|
||||||
|
*/
|
||||||
|
@Prop() mode: 'ios' | 'md';
|
||||||
|
|
||||||
@Prop() component: any;
|
@Prop() component: any;
|
||||||
@Prop() data: any = {};
|
@Prop() data: any = {};
|
||||||
@Prop() cssClass: string;
|
@Prop() cssClass: string;
|
||||||
|
@ -67,8 +67,20 @@ export class Popover {
|
|||||||
@Prop({ context: 'config' }) config: Config;
|
@Prop({ context: 'config' }) config: Config;
|
||||||
@Prop({ context: 'dom' }) dom: DomController;
|
@Prop({ context: 'dom' }) dom: DomController;
|
||||||
|
|
||||||
@Prop() mode: string;
|
/**
|
||||||
|
* @input {string} The color to use from your Sass `$colors` map.
|
||||||
|
* Default options are: `"primary"`, `"secondary"`, `"danger"`, `"light"`, and `"dark"`.
|
||||||
|
* For more information, see [Theming your App](/docs/theming/theming-your-app).
|
||||||
|
*/
|
||||||
@Prop() color: string;
|
@Prop() color: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @input {string} The mode determines which platform styles to use.
|
||||||
|
* Possible values are: `"ios"` or `"md"`.
|
||||||
|
* For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
|
||||||
|
*/
|
||||||
|
@Prop() mode: 'ios' | 'md';
|
||||||
|
|
||||||
@Prop() component: string;
|
@Prop() component: string;
|
||||||
@Prop() data: any = {};
|
@Prop() data: any = {};
|
||||||
@Prop() cssClass: string;
|
@Prop() cssClass: string;
|
||||||
|
@ -49,9 +49,6 @@ export class ReorderGroup {
|
|||||||
|
|
||||||
@Prop() disabled = true;
|
@Prop() disabled = true;
|
||||||
|
|
||||||
/**
|
|
||||||
* @input {string} Which side of the view the ion-reorder should be placed. Default `"end"`.
|
|
||||||
*/
|
|
||||||
@Watch('disabled')
|
@Watch('disabled')
|
||||||
protected disabledChanged(disabled: boolean) {
|
protected disabledChanged(disabled: boolean) {
|
||||||
if (!disabled) {
|
if (!disabled) {
|
||||||
|
@ -15,9 +15,8 @@ export class Scroll {
|
|||||||
private tmr: any;
|
private tmr: any;
|
||||||
private queued = false;
|
private queued = false;
|
||||||
private app: HTMLIonAppElement;
|
private app: HTMLIonAppElement;
|
||||||
|
private isScrolling = false;
|
||||||
isScrolling = false;
|
private detail: ScrollDetail = {};
|
||||||
detail: ScrollDetail = {};
|
|
||||||
|
|
||||||
@Element() private el: HTMLElement;
|
@Element() private el: HTMLElement;
|
||||||
|
|
||||||
@ -197,6 +196,7 @@ export class Scroll {
|
|||||||
// ******** DOM READ ****************
|
// ******** DOM READ ****************
|
||||||
detail.scrollLeft = el.scrollLeft;
|
detail.scrollLeft = el.scrollLeft;
|
||||||
|
|
||||||
|
|
||||||
if (!this.isScrolling) {
|
if (!this.isScrolling) {
|
||||||
// currently not scrolling, so this is a scroll start
|
// currently not scrolling, so this is a scroll start
|
||||||
this.isScrolling = true;
|
this.isScrolling = true;
|
||||||
@ -214,34 +214,33 @@ export class Scroll {
|
|||||||
}
|
}
|
||||||
this.ionScrollStart.emit(detail);
|
this.ionScrollStart.emit(detail);
|
||||||
}
|
}
|
||||||
|
detail.deltaY = (detail.scrollTop - detail.startY);
|
||||||
|
detail.deltaX = (detail.scrollLeft - detail.startX);
|
||||||
|
|
||||||
// actively scrolling
|
// actively scrolling
|
||||||
positions.push(detail.scrollTop, detail.scrollLeft, detail.timeStamp);
|
positions.push(detail.scrollTop, detail.scrollLeft, detail.timeStamp);
|
||||||
|
|
||||||
if (positions.length > 3) {
|
|
||||||
// we've gotten at least 2 scroll events so far
|
|
||||||
detail.deltaY = (detail.scrollTop - detail.startY);
|
|
||||||
detail.deltaX = (detail.scrollLeft - detail.startX);
|
|
||||||
|
|
||||||
const endPos = (positions.length - 1);
|
|
||||||
let startPos = endPos;
|
|
||||||
const timeRange = (detail.timeStamp - 100);
|
|
||||||
|
|
||||||
// move pointer to position measured 100ms ago
|
// move pointer to position measured 100ms ago
|
||||||
for (let i = endPos; i > 0 && positions[i] > timeRange; i -= 3) {
|
const timeRange = timeStamp - 100;
|
||||||
startPos = i;
|
let startPos = positions.length - 1;
|
||||||
|
|
||||||
|
while (startPos > 0 && positions[startPos] > timeRange) {
|
||||||
|
startPos -= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startPos !== endPos) {
|
if (startPos > 3) {
|
||||||
// compute relative movement between these two points
|
// compute relative movement between these two points
|
||||||
const deltaY = (positions[startPos - 2] - positions[endPos - 2]);
|
const frequency = 1 / (positions[startPos] - timeStamp);
|
||||||
const deltaX = (positions[startPos - 1] - positions[endPos - 1]);
|
const movedY = positions[startPos - 1] - detail.scrollLeft;
|
||||||
const factor = 1 / (positions[startPos] - positions[endPos]);
|
const movedX = positions[startPos - 2] - detail.scrollTop;
|
||||||
|
|
||||||
// based on XXms compute the movement to apply for each render step
|
// based on XXms compute the movement to apply for each render step
|
||||||
detail.velocityY = deltaY * factor;
|
// velocity = space/time = s*(1/t) = s*frequency
|
||||||
detail.velocityX = deltaX * factor;
|
detail.velocityX = movedX * frequency;
|
||||||
}
|
detail.velocityY = movedY * frequency;
|
||||||
|
} else {
|
||||||
|
detail.velocityX = 0;
|
||||||
|
detail.velocityY = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearTimeout(this.tmr);
|
clearTimeout(this.tmr);
|
||||||
|
Reference in New Issue
Block a user