mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Compare commits
1 Commits
cb/react-o
...
ld/inf-scr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c65fc7d2a |
@@ -84,6 +84,9 @@ export class InfiniteScroll implements ComponentInterface {
|
|||||||
*/
|
*/
|
||||||
@Event() ionInfinite!: EventEmitter<void>;
|
@Event() ionInfinite!: EventEmitter<void>;
|
||||||
|
|
||||||
|
|
||||||
|
private scrollHeight: number = 0;
|
||||||
|
|
||||||
async connectedCallback() {
|
async connectedCallback() {
|
||||||
const contentEl = findClosestIonContent(this.el);
|
const contentEl = findClosestIonContent(this.el);
|
||||||
if (!contentEl) {
|
if (!contentEl) {
|
||||||
@@ -102,6 +105,33 @@ export class InfiniteScroll implements ComponentInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async componentDidLoad() {
|
||||||
|
const contentEl = findClosestIonContent(this.el)!;
|
||||||
|
const scrollEl = await getScrollElement(contentEl);
|
||||||
|
const mo = new MutationObserver(async () => {
|
||||||
|
// wait for items to by hydrated so they have a dimension
|
||||||
|
const item = document.querySelectorAll('ion-item');
|
||||||
|
const lastItem = item[0];
|
||||||
|
await lastItem.componentOnReady();
|
||||||
|
|
||||||
|
// restore scroll position
|
||||||
|
const newScrollTop = scrollEl.scrollHeight - this.scrollHeight;
|
||||||
|
|
||||||
|
// TODO not sure why we need to set scrollTop twice
|
||||||
|
// TODO every once in a while the first ionInfinite callback
|
||||||
|
// still has a flicker
|
||||||
|
scrollEl.scrollTop = newScrollTop;
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
scrollEl.scrollTop = newScrollTop;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.isBusy = false;
|
||||||
|
this.didFire = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
mo.observe(findClosestIonContent(this.el)!, { subtree: true, characterData: true, childList: true });
|
||||||
|
}
|
||||||
|
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
this.enableScrollEvents(false);
|
this.enableScrollEvents(false);
|
||||||
this.scrollEl = undefined;
|
this.scrollEl = undefined;
|
||||||
@@ -132,6 +162,10 @@ export class InfiniteScroll implements ComponentInterface {
|
|||||||
if (!this.didFire) {
|
if (!this.didFire) {
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
this.didFire = true;
|
this.didFire = true;
|
||||||
|
|
||||||
|
// cache the scroll position before the DOM updates
|
||||||
|
this.scrollHeight = scrollEl.scrollHeight;
|
||||||
|
|
||||||
this.ionInfinite.emit();
|
this.ionInfinite.emit();
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
@@ -179,28 +213,6 @@ export class InfiniteScroll implements ComponentInterface {
|
|||||||
* Done.
|
* Done.
|
||||||
*/
|
*/
|
||||||
this.isBusy = true;
|
this.isBusy = true;
|
||||||
// ******** DOM READ ****************
|
|
||||||
// Save the current content dimensions before the UI updates
|
|
||||||
const prev = scrollEl.scrollHeight - scrollEl.scrollTop;
|
|
||||||
|
|
||||||
// ******** DOM READ ****************
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
readTask(() => {
|
|
||||||
// UI has updated, save the new content dimensions
|
|
||||||
const scrollHeight = scrollEl.scrollHeight;
|
|
||||||
// New content was added on top, so the scroll position should be changed immediately to prevent it from jumping around
|
|
||||||
const newScrollTop = scrollHeight - prev;
|
|
||||||
|
|
||||||
// ******** DOM WRITE ****************
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
writeTask(() => {
|
|
||||||
scrollEl.scrollTop = newScrollTop;
|
|
||||||
this.isBusy = false;
|
|
||||||
this.didFire = false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
this.didFire = false;
|
this.didFire = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||||
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@@ -19,42 +20,49 @@
|
|||||||
<ion-header>
|
<ion-header>
|
||||||
<ion-toolbar>
|
<ion-toolbar>
|
||||||
<ion-title>Infinite Scroll - Basic</ion-title>
|
<ion-title>Infinite Scroll - Basic</ion-title>
|
||||||
|
<ion-buttons slot="end">
|
||||||
|
<ion-button onclick="doScroll()">scroll to top</ion-button>
|
||||||
|
</ion-buttons>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding" id="content">
|
<ion-content class="ion-padding" id="content">
|
||||||
<ion-button onclick="toggleInfiniteScroll()" expand="block"> Toggle InfiniteScroll </ion-button>
|
<ion-infinite-scroll position="top" threshold="100px" id="infinite-scroll">
|
||||||
|
|
||||||
<ion-list id="list"></ion-list>
|
|
||||||
|
|
||||||
<ion-infinite-scroll threshold="100px" id="infinite-scroll">
|
|
||||||
<ion-infinite-scroll-content loading-spinner="crescent" loading-text="Loading more data...">
|
<ion-infinite-scroll-content loading-spinner="crescent" loading-text="Loading more data...">
|
||||||
</ion-infinite-scroll-content>
|
</ion-infinite-scroll-content>
|
||||||
</ion-infinite-scroll>
|
</ion-infinite-scroll>
|
||||||
|
|
||||||
|
<ion-list id="list"></ion-list>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
</ion-app>
|
</ion-app>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const list = document.getElementById('list');
|
const list = document.getElementById('list');
|
||||||
const infiniteScroll = document.getElementById('infinite-scroll');
|
const infiniteScroll = document.getElementById('infinite-scroll');
|
||||||
|
const content = document.querySelector('ion-content');
|
||||||
|
|
||||||
|
let count = 0;
|
||||||
function toggleInfiniteScroll() {
|
function toggleInfiniteScroll() {
|
||||||
infiniteScroll.disabled = !infiniteScroll.disabled;
|
infiniteScroll.disabled = !infiniteScroll.disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
infiniteScroll.addEventListener('ionInfinite', async function () {
|
infiniteScroll.addEventListener('ionInfinite', async function () {
|
||||||
await wait(500);
|
await wait(500);
|
||||||
infiniteScroll.complete();
|
|
||||||
appendItems();
|
appendItems();
|
||||||
|
infiniteScroll.complete();
|
||||||
|
|
||||||
// Custom event consumed in the e2e tests
|
// Custom event consumed in the e2e tests
|
||||||
window.dispatchEvent(new CustomEvent('ionInfiniteComplete'));
|
window.dispatchEvent(new CustomEvent('ionInfiniteComplete'));
|
||||||
});
|
});
|
||||||
|
|
||||||
function appendItems() {
|
function appendItems() {
|
||||||
for (var i = 0; i < 30; i++) {
|
const c = count;
|
||||||
|
for (var i = count; i < c + 30; i++) {
|
||||||
const el = document.createElement('ion-item');
|
const el = document.createElement('ion-item');
|
||||||
el.textContent = `${1 + i}`;
|
el.textContent = `${1 + i}`;
|
||||||
list.appendChild(el);
|
list.prepend(el);
|
||||||
|
count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,6 +75,25 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
appendItems();
|
appendItems();
|
||||||
|
|
||||||
|
// this piece is only needed if items are Ionic components instead of divs
|
||||||
|
// wait for Angular to load items into the DOM
|
||||||
|
const observer = new MutationObserver(async () => {
|
||||||
|
const firstItem = document.querySelector('ion-item');
|
||||||
|
|
||||||
|
// wait for item component to be hydrated
|
||||||
|
await firstItem.componentOnReady();
|
||||||
|
|
||||||
|
observer.disconnect();
|
||||||
|
|
||||||
|
content.scrollToBottom();
|
||||||
|
});
|
||||||
|
|
||||||
|
observer.observe(list, { childList: true });
|
||||||
|
|
||||||
|
const doScroll = () => {
|
||||||
|
content.scrollToTop();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user