Структурные директивы Angular и их микросинтаксис

Структурные директивы Angular и их микросинтаксис

Смотрите эту и многие другие статьи на сайте lucaspaganini.com

Вы когда-нибудь задумывались, что это за звездный префикс для *ngIf и *ngFor? Это называется структурная директива.

В этой статье я покажу вам, что это такое, когда она может понадобиться и как она работает.

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

Шаблоны — это структура

Давайте начнем определять, что это такое.

Структурная директива — это директива со структурой. Структура — это ng-шаблон.
Когда вы пишете <div><p>Text</p></div>, вы говорите Angular «объявить структуру тега div, с тегом абзаца, со строкой «Text», и отрисовать ее».

Но когда вы обернете его в <ng-template><div><p>Text</p></div></ng-template>, вы скажете Angular «объявить структуру тега div, с тегом абзаца, со строкой «Text»». Но обратите внимание, что теперь мы не говорим Angular отрисовать его.

Теперь поместите директиву в <ng-template>, и у вас есть структурная директива:

Синтаксический сахар

Вот как работает ngIf. Angular анализирует <ng-template>, генерируя TemplateRef, который внедряется в директиву NgIf. Если условие, переданное в ngIf, истинно, шаблон отображается.

Но было бы очень неудобно создавать ng-шаблон каждый раз, когда мы хотим использовать NgIf или любую другую директиву, требующую ng-шаблон. Поэтому команда Angular создала синтаксический сахар. Что-то вроде ярлыка.

Когда вы добавляете к директиве звездочку, Angular оборачивает ее в ng-шаблон и применяет директиву к ng-шаблону. Так <div *ngIf="condition">Abc</div>, становится <ng-template [ngIf]="condition"><div>Abc</div></ng-template>.

Это просто синтаксический сахар. Вы можете написать все ваше приложение без префикса звезды, если захотите.

Разрешено только одно

Зная, как это работает, вы теперь можете понять, почему мы можем использовать только одну структурную директиву на элемент. Если бы вы использовали *ngIf и *ngFor в одном и том же элементе, как бы Angular это описал? Сначала ngIf, а затем ngFor? В обратном порядке? Оба в одном шаблоне?

Микросинтаксис

Если говорить о ngFor, то он кажется намного сложнее, чем ngIf, верно? Я видел несколько действительно сложных выражений ngFor, таких как передача функции trackBy, передача массива observable, захват индекса и проверка, является ли он последним элементом.

<div *ngFor="let item of list$ | async; trackBy: trackByFn; let itemIndex = index; let islast = last">{{ item }}</div>
Вход в полноэкранный режим Выход из полноэкранного режима

Сначала я думал, что это специфический жаргон для ngFor, но это не так. Это полностью документированный синтаксис, который работает для любых структурных директив, даже тех, которые вы сами создаете. Он называется «микросинтаксис структурных директив». (вроде как очевидно).

Микросинтаксис структурных директив разделяет выражения точкой с запятой (;). В нашем примере NgFor у нас будет 4 выражения:

  1. let item of list$ | async
  2. trackBy: trackByFn
  3. let itemIndex = index
  4. let islast = last

Декларации

Выражения, начинающиеся с let, являются объявлениями переменных. Вы объявляете имя переменной сразу после let и используете знак равенства (=), чтобы указать на имя переменной в контексте экспортируемой директивы.

Это было много, извините.

Я имею в виду, что когда мы рендерим <ng-template>, мы можем опционально передать объект контекста. И свойства этого контекстного объекта передаются шаблону. Объект контекста может иметь несколько явных переменных и одну неявную переменную.

<!-- Rendering an <ng-template> with a context object -->
<ng-container *ngTemplateOutlet="templateExample; context: { $implicit: 'test', index: 1 }"></ng-container>

<!-- Using the context properties in the <ng-template> -->
<ng-template #templateExample let-itemIndex="index" let-item>
  <p>#{{ itemIndex }} - {{ item }}</p>
</ng-template>
Вход в полноэкранный режим Выход из полноэкранного режима

Это похоже на функцию JavaScript, у нас есть параметры, которые мы объявляем и, таким образом, они очень явные, и есть this, которая является неявной переменной, которая существует, даже если мы ее не объявили.

function example(itemIndex, isLast) {
  // Explicit
  console.log(itemIndex, isLast);

  // Implicit
  console.log(this);
}
Вход в полноэкранный режим Выход из полноэкранного режима

В функции вы можете иметь сколько угодно параметров, но только один this. Точно так же в ng-шаблоне вы можете иметь сколько угодно явных переменных, но только одну неявную переменную.

Неявная переменная — это то, что вы получаете, когда не указываете ни на одну экспортируемую переменную. Например, let item получает неявную переменную. Но let isLast = last получает явную переменную last, а let itemIndex = index получает явную переменную index.

После десуггерирования переменных мы получаем вот что:

<ng-template let-item let-itemIndex="index" let-isLast="last">
    <p>#{{ itemIndex }} - {{ item }}</p>
    <p *ngIf="isLast">The end</p>
</ng-template>
Вход в полноэкранный режим Выход из полноэкранного режима

Ключевые выражения

Выражения с двумя аргументами и необязательным двоеточием (:) между ними являются ключевыми выражениями. Выражение (справа) назначается на клавишу (слева) с префиксом перед ней.

Давайте рассмотрим несколько примеров.

В *ngIf="условие; else otherTemplate, для выражения else otherTemplate:

  • ngIf — префикс
  • else — ключ
  • otherTemplate — выражение

Это обесценивается до <ng-template [ngIfElse]="otherTemplate"></ng-template>.

В *ngFor="let item of list; trackBy: trackByFn, для выражения trackBy: trackByFn:

  • ngFor — префикс
  • trackBy — ключ
  • trackByFn — выражение

В результате получается <ng-template [ngForTrackBy]="trackByFn"></ng-template>.

Также, для этого примера NgFor, of list в let item of list ВСЕГДА является ключевым выражением.

  • ngFor — это префикс
  • of — ключ
  • list — выражение

Это обесценивается до <ng-template [ngForOf]="list"></ng-template>.

Локальные привязки

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

*ngIf="condition as value" становится <ng-template [ngIf]="condition" let-value="ngIf">.

Заключение

Вот и все. Теперь вы понимаете, как работают структурные директивы и как анализировать их микросинтаксис.

Я напишу еще одну статью о том, как написать собственную структурную директиву с нуля и как указать компилятору Angular проверять тип ее контекста.

Хорошего дня и до скорой встречи!

Ссылки

  1. Документация по структурным директивам Angular docs
  2. Реализация директивы NgIf на GitHub

Оцените статью
Procodings.ru
Добавить комментарий