diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 155cfbff9a..2ac023504f 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -671,6 +671,7 @@ export namespace Components { * If `true`, the content will scroll behind the headers and footers. This effect can easily be seen by setting the toolbar to transparent. */ "fullscreen": boolean; + "getBackgroundElement": () => Promise; /** * Get the element where the actual scrolling takes place. This element can be used to subscribe to `scroll` events or manually modify `scrollTop`. However, it's recommended to use the API provided by `ion-content`: i.e. Using `ionScroll`, `ionScrollStart`, `ionScrollEnd` for scrolling events and `scrollToPoint()` to scroll the content into a certain point. */ diff --git a/core/src/components/content/content.tsx b/core/src/components/content/content.tsx index 0e71c2b8bf..d5dedb69d8 100644 --- a/core/src/components/content/content.tsx +++ b/core/src/components/content/content.tsx @@ -28,6 +28,7 @@ export class Content implements ComponentInterface { private cTop = -1; private cBottom = -1; private scrollEl?: HTMLElement; + private backgroundContentEl?: HTMLElement; private isMainContent = true; // Detail is used in a hot loop in the scroll event, by allocating it here @@ -188,6 +189,18 @@ export class Content implements ComponentInterface { return Promise.resolve(this.scrollEl!); } + /** + * Returns the background content element. + * @internal + */ + @Method() + async getBackgroundElement(): Promise { + if (!this.backgroundContentEl) { + await new Promise((resolve) => componentOnReady(this.el, resolve)); + } + return Promise.resolve(this.backgroundContentEl!); + } + /** * Scroll to the top of the component. * @@ -332,7 +345,7 @@ export class Content implements ComponentInterface { '--offset-bottom': `${this.cBottom}px`, }} > -
+
(this.backgroundContentEl = el)} id="background-content" part="background">
'); return; } - const contentEl = this.el.closest(ION_CONTENT_ELEMENT_SELECTOR); if (!contentEl) { printIonContentErrorMsg(this.el); return; } - + /** + * Waits for the content to be ready before querying the scroll + * or the background content element. + */ + await contentEl.componentOnReady(); const customScrollTarget = contentEl.querySelector(ION_CONTENT_CLASS_SELECTOR); - /** * Query the custom scroll target (if available), first. In refresher implementations, * the ion-refresher element will always be a direct child of ion-content (slot="fixed"). By @@ -459,18 +461,10 @@ export class Refresher implements ComponentInterface { * the correct scroll element will be returned by the implementation. */ this.scrollEl = await getScrollElement(customScrollTarget ?? contentEl); - /** - * Query the host `ion-content` directly (if it is available), to use its - * inner #background-content has the target. Otherwise fallback to the - * custom scroll target host. - * - * This makes it so that implementers do not need to re-create the background content - * element and styles. + * Query the background content element from the host ion-content element directly. */ - this.backgroundContentEl = getElementRoot(contentEl ?? customScrollTarget).querySelector( - '#background-content' - ) as HTMLElement; + this.backgroundContentEl = await contentEl.getBackgroundElement(); if (await shouldUseNativeRefresher(this.el, getIonMode(this))) { this.setupNativeRefresher(contentEl);