Как реализован цикл 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';
}
}
Если вы включите производственный режим, эта функция больше не будет вызываться, проверьте поршень.