Трафарет JS Событие прокрутки IonContent запускает дочерний компонент - PullRequest
1 голос
/ 16 января 2020

IonContent имеет свое собственное событие прокрутки, которое мне нужно прослушивать в дочернем компоненте.

Я прослушивал событие прокрутки окна, которое не было запущено, и я понял, что оно заключено в элемент IonContent, который обрабатывает свои собственные события прокрутки.

Пример моего макета ниже

<ion-content scrollEvents={ true } onIonScroll={ this.windowScrolled.bind(this) }>
    <bf-filter-selections scrollElement={this.ionContent} ref={(e) => this.filterElementWrapper = e}></bf-filter-selections>
</ion-content>

Я пробовал несколько вещей:

  1. Я пытался вызвать Метод дочернего компонента "windowScroll" от родителя, когда происходит прокрутка на IonContent
  2. Я попытался передать ссылку на родителя дочернему элементу, чтобы я мог прослушать событие прокрутки
  3. I ' мы пытались создать свойство на дочернем объекте, которое я обновляю, когда происходит событие прокрутки, затем следим за изменениями

Это может привести к некоторым базовым c js знаниям, которых мне не хватает, но это разочаровывает, поскольку я не могу заставить событие запускаться в моем дочернем компоненте, когда содержимое прокручивается.

Из того, что я пробовал, вот почему они не работали * 102 0 *

1) Вызывая метод дочернего компонента из родительского, код сообщает мне, что он не может найти «windowScroll» для дочернего элемента.

filterElementWrapper - HTMLElement

 filterElementWrapper: any;
 windowScrolled(e: any) {

    this.filterElementWrapper.windowScroll();

  }

Метод дочернего компонента

  @Listen('onscroll')
  @Watch('scrollOffset')
  public windowScroll() {
    console.log('scroll');

    if (window.pageYOffset > this.resultHeaderElementOffset) {
      this.resultHeaderElement.classList.add("sticky");
    } else {
      this.resultHeaderElement.classList.remove("sticky");
    }
  }

2) Попытка передачи ссылки на родительский компонент дочернему элементу

У меня больше нет кода, который поддерживает это, но в основном в дочернем компоненте Я создал свойство, имеющее тип "any", и передал ссылку на родительский объект дочернему элементу.

Затем я создал «Listen ('ionScroll', {target: this.scrollElement})".

Метод никогда не запускается в дочернем элементе.

3) Создано свойство в дочернем компоненте с именем "scrollOffset". Я обновил это свойство, когда была запущена прокрутка и «Наблюдать» за изменениями свойства в дочернем компоненте. Опять же, метод не запускается.

Основная оболочка, устанавливающая свойство смещения прокрутки

<ion-content scrollEvents={ true } onIonScroll={ this.windowScrolled.bind(this) }> 
   <bf-filter-selections scroll-offset={this.scrollTop} scrollElement={this.ionContent} ref={(e) => this.filterElementWrapper = e}></bf-filter-selections>
</ion-content>

Свойство состояния, установленное в родительском

@State() scrollTop: number = 0;

Обновление свойства состояния on scroll

windowScrolled(e: any) {
    this.scrollTop = e.detail.currentY;
}

Наблюдаемое свойство потомка

@Prop() scrollOffset: number;

Изменяется метод отслеживания свойства

  @Listen('onscroll')
  @Watch('scrollOffset')
  public windowScroll() {
    console.log('scroll');

    if (window.pageYOffset > this.resultHeaderElementOffset) {
      this.resultHeaderElement.classList.add("sticky");
    } else {
      this.resultHeaderElement.classList.remove("sticky");
    }
  }

Во всех случаях метод имеет вид не вызывается.

Ответы [ 3 ]

2 голосов
/ 17 января 2020

Я не уверен на 100%, почему ваш метод 3 начал работать, но я предполагаю, что это потому, что обработчик onIonScroll обновляет состояние scrollOffset, которое затем вызывает метод @Watch().


Здесь вы перепутали несколько вещей, поэтому сначала я попытаюсь немного это прояснить: если элемент генерирует событие <EventName>, вы можете привязать слушателя к этому элементу, добавив * Свойство 1008 *, например:

<my-button onclick={console.log} />

связывает функцию console.log с событием click. Эквивалент выполнения той же вещи в JavaScript будет:

document.querySelector('my-button').addEventListener('click', console.log);

Если вы сделали addEventListener('onclick'), это не сработает, потому что имя события click, а не onclick. Вы добавляете префикс on только в том случае, если хотите добавить обработчик событий к элементу в HTML (см. Обработчики DOM onevent ). Кроме того, это также будет работать в JavaScript:

document.querySelector('my-button').onclick = console.log;

(разница в том, что вы можете установить только одно свойство onclick, но вы можете подключить несколько click прослушивателей событий, если вы используете addEventListener )

Обратите внимание, что регистр имеет значение в JavaScript, но не в HTML, поэтому

<my-button onClick={console.log} />

эквивалентно первому примеру.


В идеале я хотел прослушать событие прокрутки родительского компонента в дочернем элементе, и до сих пор не могу заставить его работать.

Это невозможно, потому что события могут только всплывать в DOM-дереве, но не вниз. Концепция "события вверх, подпорки". Для вашего случая самое чистое решение, которое я могу придумать, похоже на то, что вы уже пробовали: прослушайте событие у родителя, а затем передайте необходимую информацию ребенку в качестве опоры:

import { h, Component, State } from '@stencil/core';
import { ScrollDetail } from '@ionic/core';

@Component({ tag: 'my-parent' })
export class Parent {
  @State() scrollTop = 0;

  setScrollTop = (e: CustomEvent<ScrollDetail>) => {
    this.scrollTop = e.detail.scrollTop;
  }

  render() {
    return (
      <ion-content scrollEvents onIonScroll={this.setScrollTop}>
        <child-component scrollTop={this.scrollTop} />
      </ion-content>
    );
  }
}

Вместо используя onIonScroll в качестве свойства <ion-content>, вы также можете использовать декоратор @Listen() следующим образом:

@Listen('ionScroll')
setScrollTop(e: CustomEvent<ScrollDetail>) {
  this.scrollTop = e.detail.scrollTop;
}

Здесь ваша ошибка заключалась в использовании 'onscroll' в качестве имени события.


Я видел, что вы также пытались передать ссылку на элемент прокрутки дочернему элементу. Элемент ion-content не тот, который фактически прокручивается, поэтому он предоставляет метод getScrollElement, который дает вам правильный элемент, если вы хотите сделать «нативную» вещь, например, доступ к базовому событию scroll или вручную получить доступ к scrollTop этого элемента (я полагаю, это то, что вы пытались сделать от своего ребенка).

customElements.whenDefined('ion-content').then(() => {
  document.querySelector('ion-content').getScrollElement().then(el => {
    el.addEventListener('scroll', () => console.log(el.scrollTop));
  });
});
0 голосов
/ 17 января 2020

Лично я бы go за первый, потому что он ближайший к прерыванию / pu sh. Поэтому, если состояние изменяется, дочерний компонент немедленно получает информацию об изменении состояния.

Вы были действительно близки, но вам просто нужно добавить декоратор @ Method к вашей дочерней функции. Этот декоратор делает доступной функцию publi c, и вы можете вызывать ее у родителя. С моей точки зрения, это самый простой и лучший способ реализовать это.

Просто побочное замечание для вашего второго и третьего решения: обе концепции начали работать, потому что трафарет следит за свойствами и отображает компонент, когда изменение было применено. В некоторых случаях это не нужно - это создает нежелательные накладные расходы. Кроме того, я думаю, что часы на самом деле спроектированы как опросы, но я не уверен в этом.

Кроме того, вы не можете получить родительское событие, так как поведение события похоже - оно начинается с root и «спускается» через дерево, пока не достигнет взаимодействующего элемента. Это называется фаза захвата . Как только оно достигло элемента, оно лопнуло. Таким образом, теоретически события go вниз и вы можете захватить их , но только если элемент находится выше в иерархии, тогда взаимодействие было.

0 голосов
/ 16 января 2020

По какой-то причине метод 3 начал работать.

Я не уверен, что это потому, что я выполнил чистую сборку проекта после публикации обновлений, но метод теперь вызывается и все работает, как и ожидалось.

Одна вещь, я все еще хотел бы знать, является ли это лучшим подходом? В идеале я хотел прослушать событие прокрутки родительского компонента в дочернем элементе, и я до сих пор не могу заставить его работать.

Если у кого-то есть более чистое решение, пожалуйста, дайте мне знать

...