fix(refresher): refresher is visible with multiple custom scroll targets (#25750)

Resolves #25495
This commit is contained in:
Sean Perkins
2022-08-15 14:58:38 -04:00
committed by GitHub
parent f47c5de1e6
commit e750e33616
3 changed files with 22 additions and 14 deletions

View File

@ -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. * 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; "fullscreen": boolean;
"getBackgroundElement": () => Promise<HTMLElement>;
/** /**
* 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. * 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.
*/ */

View File

@ -28,6 +28,7 @@ export class Content implements ComponentInterface {
private cTop = -1; private cTop = -1;
private cBottom = -1; private cBottom = -1;
private scrollEl?: HTMLElement; private scrollEl?: HTMLElement;
private backgroundContentEl?: HTMLElement;
private isMainContent = true; private isMainContent = true;
// Detail is used in a hot loop in the scroll event, by allocating it here // 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!); return Promise.resolve(this.scrollEl!);
} }
/**
* Returns the background content element.
* @internal
*/
@Method()
async getBackgroundElement(): Promise<HTMLElement> {
if (!this.backgroundContentEl) {
await new Promise((resolve) => componentOnReady(this.el, resolve));
}
return Promise.resolve(this.backgroundContentEl!);
}
/** /**
* Scroll to the top of the component. * Scroll to the top of the component.
* *
@ -332,7 +345,7 @@ export class Content implements ComponentInterface {
'--offset-bottom': `${this.cBottom}px`, '--offset-bottom': `${this.cBottom}px`,
}} }}
> >
<div id="background-content" part="background"></div> <div ref={(el) => (this.backgroundContentEl = el)} id="background-content" part="background"></div>
<TagType <TagType
class={{ class={{
'inner-scroll': true, 'inner-scroll': true,

View File

@ -443,15 +443,17 @@ export class Refresher implements ComponentInterface {
console.error('Make sure you use: <ion-refresher slot="fixed">'); console.error('Make sure you use: <ion-refresher slot="fixed">');
return; return;
} }
const contentEl = this.el.closest(ION_CONTENT_ELEMENT_SELECTOR); const contentEl = this.el.closest(ION_CONTENT_ELEMENT_SELECTOR);
if (!contentEl) { if (!contentEl) {
printIonContentErrorMsg(this.el); printIonContentErrorMsg(this.el);
return; 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); const customScrollTarget = contentEl.querySelector(ION_CONTENT_CLASS_SELECTOR);
/** /**
* Query the custom scroll target (if available), first. In refresher implementations, * 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 * 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. * the correct scroll element will be returned by the implementation.
*/ */
this.scrollEl = await getScrollElement(customScrollTarget ?? contentEl); this.scrollEl = await getScrollElement(customScrollTarget ?? contentEl);
/** /**
* Query the host `ion-content` directly (if it is available), to use its * Query the background content element from the host ion-content element directly.
* 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.
*/ */
this.backgroundContentEl = getElementRoot(contentEl ?? customScrollTarget).querySelector( this.backgroundContentEl = await contentEl.getBackgroundElement();
'#background-content'
) as HTMLElement;
if (await shouldUseNativeRefresher(this.el, getIonMode(this))) { if (await shouldUseNativeRefresher(this.el, getIonMode(this))) {
this.setupNativeRefresher(contentEl); this.setupNativeRefresher(contentEl);