Как реализован цикл Angular *ngFor?

Интересно, как работает Angular *ngFor Директива на самом деле работает под капотом? Я хотел бы знать весь процесс, который происходит, когда я использую директиву.

Для downvoters: я видел файл ng-for-of, хотя нет единственного использования переданного в *ngFor например, массив join() метод, который я знаю, вызывается. Спасибо за вашу поддержку:) Вот плункер, который показывает поведение: https://plnkr.co/edit/IXVxWrSOhLBgvSal6PWL?p=preview

1 ответ

Решение

Вот обзор высокого уровня. Предположим, вы определили свой шаблон следующим образом:

<span *ngFor="let item of items">{{item}}</span>

Затем он преобразуется компилятором в следующее:

<ng-template let-item [ngForOf]="items">
    <span>{{item}}</span>
</ng-template>

Тогда применяется Angular ngForOf директива к элементу шаблона. Поскольку элемент host этой директивы - это template, он внедряет templateRef, Он также вводит viewContainerRef который действует как элемент привязки и будет использоваться для добавления элементов DOM вместе с:

  constructor(
       private _viewContainer: ViewContainerRef, 
       private _template: TemplateRef<NgForOfContext<T>>,

Директива определяет ngForOf в качестве входных данных, а затем ждет, пока он будет инициализирован и создает разницу:

  ngOnChanges(changes: SimpleChanges): void {
      const value = changes['ngForOf'].currentValue;
          this._differ = this._differs.find(value).create(this.ngForTrackBy);

Затем в каждом цикле обнаружения проверки он сравнивает значения с предыдущими значениями, используя это различие:

  ngDoCheck(): void {
    if (this._differ) {
      const changes = this._differ.diff(this.ngForOf);
      if (changes) this._applyChanges(changes);
    }
  }

Если значения изменились, он применяет изменения, выполняя следующие действия:

1) генерирует контекст встроенного представления для каждого элемента в items

context = new NgForOfContext<T>(null !, this.ngForOf, -1, -1)

2) создает встроенное представление с этим контекстом, используя templateRef который эффективно оказывает новое значение в DOM

this._viewContainer.createEmbeddedView(
                this._template, context , currentIndex);

3) добавляет соответствующие значения в контекст

  viewRef.context.index = i;
  viewRef.context.count = ilen;
  viewRef.context.$implicit = record.item;`

Теперь ваш вопрос:

хотя это не объясняет, почему метод e..g join() вызывается для массива, переданного в

Вызывается функцией normalizeDebugBindingValue здесь, потому что ваше приложение работает в режиме разработки:

function normalizeDebugBindingValue(value: any): string {
  try {
    // Limit the size of the value as otherwise the DOM just gets polluted.
    return value != null ? value.toString().slice(0, 30) : value;
                           ^^^^^^^^^^^^^^^
  } catch (e) {
    return '[ERROR] Exception while trying to serialize the value';
  }
}

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

Другие вопросы по тегам