fix(all): component reusage (#18963)

Use new stencil APIs to allow ionic elements to be reused once removed from the DOM.

fixes #18843
fixes #17344
fixes #16453
fixes #15879
fixes #15788
fixes #15484
fixes #17890
fixes #16364
This commit is contained in:
Manu MA
2019-08-27 16:29:37 +02:00
committed by GitHub
parent a65d897214
commit 48a27636c7
33 changed files with 411 additions and 368 deletions

View File

@ -1,4 +1,4 @@
import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Listen, Method, Prop, Watch, h } from '@stencil/core';
import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, Watch, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { rIC } from '../../utils/helpers.js';
@ -20,8 +20,8 @@ export class Slides implements ComponentInterface {
private scrollbarEl?: HTMLElement;
private paginationEl?: HTMLElement;
private didInit = false;
private swiperReady = false;
private mutationO?: MutationObserver;
private readySwiper!: (swiper: SwiperInterface) => void;
private swiper: Promise<SwiperInterface> = new Promise(resolve => { this.readySwiper = resolve; });
@ -35,7 +35,7 @@ export class Slides implements ComponentInterface {
@Watch('options')
async optionsChanged() {
if (this.didInit) {
if (this.swiperReady) {
const swiper = await this.getSwiper();
Object.assign(swiper.params, this.options);
await this.update();
@ -132,20 +132,28 @@ export class Slides implements ComponentInterface {
*/
@Event() ionSlideTouchEnd!: EventEmitter<void>;
componentDidLoad() {
connectedCallback() {
const mut = this.mutationO = new MutationObserver(() => {
if (this.swiperReady) {
this.update();
}
});
mut.observe(this.el, {
childList: true,
subtree: true
});
rIC(() => this.initSwiper());
}
async componentDidUnload() {
async disconnectedCallback() {
if (this.mutationO) {
this.mutationO.disconnect();
this.mutationO = undefined;
}
const swiper = await this.getSwiper();
swiper.destroy(true, true);
}
@Listen('ionSlideChanged')
onSlideChanged() {
if (this.didInit) {
this.update();
}
this.swiper = new Promise(resolve => { this.readySwiper = resolve; });
this.swiperReady = false;
}
/**
@ -154,7 +162,10 @@ export class Slides implements ComponentInterface {
*/
@Method()
async update() {
const swiper = await this.getSwiper();
const [swiper] = await Promise.all([
this.getSwiper(),
waitForSlides(this.el)
]);
swiper.update();
}
@ -315,8 +326,9 @@ export class Slides implements ComponentInterface {
// init swiper core
// @ts-ignore
const { Swiper } = await import('./swiper/swiper.bundle.js');
await waitForSlides(this.el);
const swiper = new Swiper(this.el, finalOptions);
this.didInit = true;
this.swiperReady = true;
this.readySwiper(swiper);
}
@ -485,3 +497,9 @@ export class Slides implements ComponentInterface {
);
}
}
const waitForSlides = (el: HTMLElement) => {
return Promise.all(
Array.from(el.querySelectorAll('ion-slide')).map(s => s.componentOnReady())
);
};