243 lines
26 KiB
Markdown
243 lines
26 KiB
Markdown
---
|
||
title: Views
|
||
localeTitle: Просмотры
|
||
---
|
||
# Просмотры
|
||
|
||
#### мотивация
|
||
|
||
Представления предлагают необходимый уровень абстракции. Они сохраняют Угловую независимость от конкретных утилит платформы. В качестве кросс-платформенной технологии Angular использует свои возможности для подключения к платформе.
|
||
|
||
Для каждого элемента HTML шаблона Angular существует соответствующее представление. Angular рекомендует взаимодействовать с платформами через эти представления. Хотя прямые манипуляции все еще возможны, Angular предупреждает об этом. Angular предлагает собственный интерфейс прикладного программирования (API) для замены собственных манипуляций.
|
||
|
||
Отказ от просмотра API-интерфейса для платформы имеет свои последствия. При разработке Angular в веб-браузере элементы существуют в двух местах: DOM и представлении. Мессинг только с DOM не влияет на представление.
|
||
|
||
Поскольку Angular не взаимодействует с платформой, это создает разрыв. Представления должны зеркально отображать платформу один к одному. В противном случае Угловые ресурсы отходов управляют элементами, которые не соответствуют им. Это ужасно в случае удаленных элементов.
|
||
|
||
Подобные расхождения делают взгляды ненужными. Никогда не забывайте, что Angular является универсальной платформой развития, прежде всего. Представления являются необходимой абстракцией для этой цели.
|
||
|
||
Соблюдая взгляды, угловые приложения будут работать на всех поддерживаемых платформах разработки. Платформы включают в себя Web, Android и Apple iOS.
|
||
|
||
#### Заметка
|
||
|
||
Отсюда, эта статья предполагает среду веб-браузера. Не стесняйтесь мысленно заменить DOM чем-то более применимым к вашей предпочитаемой платформе.
|
||
|
||
#### Что такое Views?
|
||
|
||
Представления почти как их собственный виртуальный DOM. Каждое представление содержит ссылку на соответствующий раздел DOM. Внутри представления находятся узлы, которые отражают то, что находится в этом разделе. Угловой присваивает один узел вида на элемент DOM. Каждый узел содержит ссылку на соответствующий элемент.
|
||
|
||
Когда Angular проверяет изменения, он проверяет представления. Угловое избегает DOM под капотом. Мнения ссылаются на DOM от его имени. Существуют и другие механизмы для обеспечения того, чтобы изменения вида отображались в DOM. И наоборот, изменения в DOM не влияют на представления.
|
||
|
||
Опять же, взгляды распространены на всех платформах разработки, кроме DOM. Даже если они разрабатываются для одной платформы, мнения по-прежнему считаются лучшей практикой. Они гарантируют, что Угловая имеет правильную интерпретацию DOM.
|
||
|
||
Представления могут отсутствовать в сторонних библиотеках. Прямая манипуляция с DOM - это экранирующий люк для такого сценария. Конечно, не ожидайте, что приложение будет работать с кросс-платформенными.
|
||
|
||
#### Типы просмотров
|
||
|
||
Существует два основных типа представлений: встроенный и хост.
|
||
|
||
Также существуют контейнеры представлений. Они содержат встроенные и хост-представления и часто называются простыми «представлениями».
|
||
|
||
Каждый класс `@Component` регистрирует контейнер вида (просмотр) с помощью Angular. Новые компоненты генерируют настраиваемый селектор, предназначенный для определенного элемента DOM. Представление прикрепляется к этому элементу везде, где оно появляется. Угловой теперь знает, что компонент существует, глядя на модель представления.
|
||
|
||
Представления хоста прикрепляются к компонентам, созданным динамически с заводами. Фабрики представляют собой основу для создания экземпляра представления. Таким образом, приложение может создавать экземпляр хоста компонента во время выполнения. Хост-представление прикрепляется к обертке компонента за его экземпляр. В этом представлении хранятся данные, описывающие возможности обычных компонентов.
|
||
|
||
`<ng-template></ng-template>` является сродни элементу HTML5 `<template></template>` . `ng-template` Angular работает со встроенными представлениями. Эти представления не привязаны к элементам DOM в отличие от представлений хоста. Они идентичны представлениям хоста, поскольку они оба типа существуют внутри контейнеров просмотра.
|
||
|
||
Имейте в виду, что `ng-template` не является элементом DOM. Он закомментирован позже, оставив только узлы встроенного представления.
|
||
|
||
Разница зависит от входных данных; встроенные представления не хранят данные компонента. Они хранят ряд элементов в качестве узлов, содержащих его шаблон. Шаблон составляет все innerHTML `ng-template` . Каждый элемент внутри встроенного представления представляет собой отдельный отдельный узел представления.
|
||
|
||
#### Представления и контейнеры для хостов
|
||
|
||
В представлениях _хоста размещаются_ динамические компоненты. Просмотреть контейнеры (виды) автоматически присоединяются к элементам, уже находящимся в шаблоне. Представления могут присоединяться к любому элементу за пределами того, что уникально для классов компонентов.
|
||
|
||
Подумайте о традиционном способе создания компонентов. Он начинается с создания класса, декорирования его с помощью `@Component` и заполнения метаданных. Этот подход применяется для любого заранее определенного элемента компонента шаблона.
|
||
|
||
Попробуйте использовать команду интерфейса командной строки (CLI): `ng generate component [name-of-component]` . Это дает следующее.
|
||
|
||
```typescript
|
||
import { Component, OnInit } from '@angular/core';
|
||
|
||
@Component({
|
||
selector: 'app-example',
|
||
templateUrl: './example.component.html',
|
||
styleUrls: ['./example.component.css']
|
||
})
|
||
export class ExampleComponent implements OnInit {
|
||
constructor() { }
|
||
|
||
ngOnInit() { }
|
||
}
|
||
```
|
||
|
||
Это создает компонент с `app-example` селектора. Это прикрепляет контейнер представления к `<app-example></app-example>` в шаблоне. Если бы это был корень приложения, его представление инкапсулировало бы все другие представления. Корневой вид обозначает начало приложения с точки зрения Углового.
|
||
|
||
Динамическое создание компонентов и их регистрация в модели с угловым видом занимает несколько дополнительных шагов. Структурные директивы помогают управлять динамическим контентом ( `*ngIf, *ngFor, and *ngSwitch…` ). Однако директивы не масштабируются для больших приложений. Слишком много структурных директив усложняет шаблон.
|
||
|
||
Именно здесь пригодится создание экземпляров из существующей логики классов. Этим компонентам необходимо создать представление хоста, которое может вставляться в модель представления. Представления хоста содержат данные для компонентов, так что Angular распознает их структурную цель.
|
||
|
||
##### Хост-просмотр продолжается
|
||
|
||
Каждый компонент имеет определение класса. Однако JavaScript не поддерживает классы. Классы - это синтаксический сахар. Вместо этого они производят функции, содержащие компоненты.
|
||
|
||
Фабрики действуют как чертежи для представлений хостов. Они создают представления для взаимодействия с Angular от имени своих компонентов. Представления хоста прикрепляются к элементам DOM. Технически любой элемент в порядке, но наиболее распространенной целью является `<ng-component></ng-component>` .
|
||
|
||
Вначале должен существовать контейнер представления (представление) для размещения представлений. `<ng-container></ng-container>` - отличное место для прикрепления контейнера вида. Контейнеры просмотра - это те же типы представлений, которые также применяются к элементам класса шаблона.
|
||
|
||
Несколько помощников и ссылки из `@angular/core` предоставляют другие необходимые утилиты. Следующий пример объединяет все это.
|
||
|
||
```typescript
|
||
// another.component.ts
|
||
|
||
import { Component } from '@angular/core';
|
||
|
||
@Component({
|
||
template: `
|
||
<h1>Another Component Content</h1>
|
||
<h3>Dynamically Generated!</h3>
|
||
`
|
||
})
|
||
export class AnotherComponent { }
|
||
```
|
||
|
||
```typescript
|
||
// example.component.ts
|
||
|
||
import { AfterViewInit, Component, ViewChild,
|
||
ViewContainerRef, ComponentFactoryResolver } from '@angular/core';
|
||
import { AnotherComponent } from './another.component';
|
||
|
||
@Component({
|
||
selector: 'app-example',
|
||
template: `
|
||
<h1>Application Content</h1>
|
||
<ng-container #container></ng-container>
|
||
<h3>End of Application</h3>
|
||
`,
|
||
entryComponents: [ AnotherComponent ]
|
||
})
|
||
export class ExampleComponent implements AfterViewInit {
|
||
@ViewChild("container", { read: ViewContainerRef }) ctr: ViewContainerRef;
|
||
|
||
constructor(private resolve: ComponentFactoryResolver) { }
|
||
|
||
ngAfterViewInit() {
|
||
const factory = this.resolve.resolveComponentFactory(AnotherComponent);
|
||
this.ctr.createComponent(factory);
|
||
}
|
||
}
|
||
```
|
||
|
||
Предположим, что AnotherComponent и ExampleComponent объявлены в том же модуле. AnotherComponent - это простой компонент класса, динамически добавленный в представление ExampleComponent. Метаданные entryComponents для `entryComponents` должны содержать AnotherComponent для [начальной загрузки](https://angular.io/guide/bootstrapping) .
|
||
|
||
Хотя ExampleComponent является частью шаблона, AnotherComponent остается отсоединенным. Он динамически отображает шаблон из ExampleComponent.
|
||
|
||
Есть два контейнера представления: `<app-example></app-example>` и `<ng-container></ng-container>` . Представление хоста для этого примера будет вставляться в `ng-container` .
|
||
|
||
`AfterViewInit` жизненного цикла `AfterViewInit` запускается после `@ViewChild` запросов `@ViewChild` . Используя _ссылочную переменную шаблона_ `#container` , `@ViewChild` ссылается на `ng-container` как `ctr` .
|
||
|
||
`ViewContainerRef` - тип ссылки для контейнеров представлений (просмотров). `ViewContainerRef` ссылается на представление, которое поддерживает вставку других представлений. `ViewContainerRef` содержит больше методов управления содержащимися представлениями.
|
||
|
||
Благодаря внедрению зависимостей конструктор создает экземпляр службы `ComponentFactoryResolver` для Angular. Эта служба извлекает заводскую функцию (схема представления хоста) AnotherComponent.
|
||
|
||
Единственный аргумент `createComponent` требует фабрики. Функция `createComponent` происходит из `ViewContainerRef` . Он создает экземпляр AnotherComponent под представлением хоста, производным от фабрики компонента.
|
||
|
||
Затем представление узла вставляется в контейнер представления. `<ng-component></ng-component>` обертывает компонент внутри контейнера представления. Он придает ему вышеупомянутый вид на хост. `ng-component` - соединение узла с DOM.
|
||
|
||
Существуют и другие способы создания динамического представления хоста из компонента. Другие способы часто [фокусируются на оптимизации](https://blog.angularindepth.com/working-with-dom-in-angular-unexpected-consequences-and-optimization-techniques-682ac09f6866) .
|
||
|
||
`ViewContainerRef` содержит мощный API. Он может управлять любым количеством представлений хостом или встроенным в его представление. API включает операции просмотра, такие как вставка, перемещение и удаление. Это позволяет вам манипулировать моделью DOM через модель Angular. Это лучшая практика, так что Angular и DOM соответствуют друг другу.
|
||
|
||
#### Встроенные представления
|
||
|
||
Примечание: встроенные представления присоединяются к другим представлениям без добавления ввода. Представления хоста присоединяются к элементу DOM с входными данными из представления своего хоста, описывая его как компонент.
|
||
|
||
Структурные директивы создают [`ng-template` окружающий кусок содержимого HTML](https://angular.io/guide/structural-directives#the-asterisk--prefix) . Элемент-хозяин директивы имеет прикрепленный контейнер вида. Это делает его таким, чтобы контент мог условно отобразить его предполагаемый макет.
|
||
|
||
В `ng-template` содержатся встроенные узлы представления, представляющие каждый элемент внутри его внутреннего HTTML. `ng-template` ни в коем случае не является элементом DOM. Он сам замечает. Теги определяют длину встроенного представления.
|
||
|
||
#### Встроенные представления продолжаются
|
||
|
||
Создание экземпляра встроенного представления не требует внешних ресурсов за пределами его собственных ссылок. Запрос `@ViewChild` может получить это.
|
||
|
||
С ссылкой на шаблон, вызов `createEmbeddedView` из него делает трюк. ВнутреннийHTML ссылки становится его собственным встроенным представлением представления.
|
||
|
||
В следующем примере `<ng-container></ng-container>` - контейнер представления. `ng-container` комментируется во время компиляции точно так же, как `ng-template` . Таким образом, он обеспечивает выход для вставки встроенного представления, сохраняя при этом DOM lean.
|
||
|
||
Встроенный шаблон просмотра вставляется в расположение расположения `ng-container` . Этот вновь вставленный вид не имеет дополнительной инкапсуляции вида, кроме контейнера представления. Помните, как это отличается от представлений хоста (представления хоста прикрепляются к их `ng-component` элемента `ng-component` ).
|
||
|
||
```typescript
|
||
import { Component, AfterViewInit, ViewChild,
|
||
ViewContainerRef, TemplateRef } from '@angular/core';
|
||
|
||
@Component({
|
||
selector: 'app-example',
|
||
template: `
|
||
<h1>Application Content</h1>
|
||
<ng-container #container></ng-container> <!-- embed view here -->
|
||
<h3>End of Application</h3>
|
||
|
||
<ng-template #template>
|
||
<h1>Template Content</h1>
|
||
<h3>Dynamically Generated!</h3>
|
||
</ng-template>
|
||
`
|
||
})
|
||
export class ExampleComponent implements AfterViewInit {
|
||
@ViewChild("template", { read: TemplateRef }) tpl: TemplateRef<any>;
|
||
@ViewChild("container", { read: ViewContainerRef }) ctr: ViewContainerRef;
|
||
|
||
constructor() { }
|
||
|
||
ngAfterViewInit() {
|
||
const view = this.tpl.createEmbeddedView(null);
|
||
this.ctr.insert(view);
|
||
}
|
||
}
|
||
```
|
||
|
||
`@ViewChild` для _ссылочной переменной шаблона_ `#template` . Это предоставляет ссылку на `TemplateRef` типа `TemplateRef` . `TemplateRef` содержит функцию `createEmbeddedView` . Он создает шаблон в виде встроенного представления.
|
||
|
||
Единственный аргумент `createEmbeddedView` предназначен для контекста. Если вы хотите передать дополнительные метаданные, вы можете сделать это здесь как объект. Поля должны совпадать с атрибутами `ng-template` ( `let-[context-field-key-name]=“value”` ). Передача `null` не требует дополнительных метаданных.
|
||
|
||
Второй запрос `@ViewChild` предоставляет ссылку на `ng-container` как `ViewContainerRef` . Встроенные представления присоединяются только к другим представлениям, а не к DOM. `ViewContainerRef` ссылается на представление, которое занимает встроенный просмотр.
|
||
|
||
Встроенный вид также может вставляться в представление компонента в `<app-example></app-example>` . Этот подход позиционирует представление в самом конце представления ExampleComponent. Однако в этом примере мы хотим, чтобы содержимое отображалось в самой середине, где находится `ng-container` .
|
||
|
||
Функция `insert` `ViewContainerRef` _вставляет_ встроенный вид в `ng-container` . Содержимое представления отображается в предполагаемом месте прямо в середине представления ExampleComponent.
|
||
|
||
#### Вывод
|
||
|
||
Манипулирование DOM с помощью специальных методов платформы не рекомендуется. Создание и управление узким набором представлений держит Angular и DOM на одной странице. Обновление представлений сообщает Угловое состояние текущего состояния DOM. Обновления представлений также переносятся на то, что отображается DOM.
|
||
|
||
Угловой обеспечивает гибкий интерфейс API для просмотра. Благодаря этому уровню абстракции возможно развитие независимых от платформы приложений. Конечно, сохраняется соблазн отказаться от стратегий, зависящих от платформы. Если у вас нет веских оснований, не пытайтесь придерживаться взглядов API Angular. Это даст прогнозируемые результаты на всех платформах.
|
||
|
||
Проверьте также ресурсы ниже! Эта статья просто царапает поверхность. В некоторых статьях есть много других случаев использования, слишком обширных для одной статьи.
|
||
|
||
## источники
|
||
|
||
* [AngularInDepth.com. «Просмотр компонентов, Просмотр хоста, Встроенный просмотр», # 40423772. 11 июля 2017. «В чем разница между представлением, представлением хоста и встроенным представлением»](https://stackoverflow.com/questions/40423772/what-is-the-difference-between-a-view-a-host-view-and-an-embedded-view)
|
||
|
||
* [Угловая команда. «Структурные директивы». _Google_ . Доступ к 31 мая 2018 года](https://angular.io/guide/structural-directives)
|
||
|
||
* [Корецкий, Максим. «Изучение методов манипуляции с угловым DOM с использованием ViewContainerRef». _Угловая глубина_ , 4 марта 2017. Доступ к 30 мая 2018 года.](https://blog.angularindepth.com/exploring-angular-dom-abstractions-80b3ebcfc02)
|
||
|
||
* [Корецкий, Максим. «Реализация расширенных сценариев манипуляции с DOM». _Youtube_ , загруженный ng-conf, 19 апреля 2018. Доступен 30 мая 2018 года](https://www.youtube.com/watch?v=vz9cNCkaPsY)
|
||
|
||
* [Корецкий, Максим. «Работа с DOM in Angular: неожиданные последствия и методы оптимизации». _Угловая глубина_ , 3 мая 2017 года. Доступ к 31 мая 2018 года](https://blog.angularindepth.com/working-with-dom-in-angular-unexpected-consequences-and-optimization-techniques-682ac09f6866)
|
||
|
||
|
||
## Ресурсы
|
||
|
||
* [Угловая документация](https://angular.io/guide/pipes)
|
||
|
||
* [Угловая глубина](https://blog.angularindepth.com)
|
||
|
||
* [ViewContainerRef](https://angular.io/api/core/ViewContainerRef)
|
||
|
||
* [TemplateRef](https://angular.io/api/core/TemplateRef)
|
||
|
||
* [Угловой репозиторий GitHub](https://github.com/angular/angular)
|
||
|
||
* [Угловая CLI](https://cli.angular.io) |