Создание компонента элемента (item component) - Изучение веб-разработки

Создание компонента элемента (item component)
=============================================

* Назад
* Обзор: Client-side JavaScript frameworks
* Далее

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

|  |  |
| --- | --- |
| Необходимые условия: | Понимание основ HTML, CSS и JavaScript знание терминала/командной строки (en-US) |
| Цель: | Изучить больше информации о компонентах, включая обработку событий, чтобы реализовать функции проверки, редактирования и удаления. |

Создание нового компонента
--------------------------

Создайте компонент с именем `item` с помощью следующих команд в командной строке:

```bash
ng generate component item
```

 Команда `ng generate component` создаст компонент и папку с указаным именем.
 Имя папки и компонента будет `item`.
 Вы можете найти дирректорию `item` внутри папки `app`.

Как и в случае с `AppComponent`, `ItemComponent` состоит из следующих файлов:

* `item.component.html` для HTML
* `item.component.ts` для логики
* `item.component.css` для стилей

Можно увидеть ссылку на файлы HTML и CSS в метаданных декоратора `@Component()` в `item.component.ts`.

```js
@Component({
  selector: 'app-item',
  templateUrl: './item.component.html',
  styleUrls: ['./item.component.css'],
})
```

Добавьте HTML для ItemComponent
-------------------------------

С помощью компонента `ItemComponent` можно будет отмечать элементы списка как выполненные, редактировать или удалять их.

Добавьте разметку для управления элементами, заменив содержимое `item.component.html` следующим кодом:

```html
<div class="item">
  <input
 [id]="item.description"
 type="checkbox"
 (change)="item.done = !item.done"
 [checked]="item.done" />
  <label [for]="item.description">{{item.description}}</label>

  <div class="btn-wrapper" \*ngIf="!editable">
    <button class="btn" (click)="editable = !editable">Edit</button>
    <button class="btn btn-warn" (click)="remove.emit()">Delete</button>
  </div>

  <!-- Этот блок отображается, если пользователь кликнул на кнопку Edit -->
  <div \*ngIf="editable">
    <input
 class="sm-text-input"
 placeholder="edit item"
 [value]="item.description"
 #editedItem
 (keyup.enter)="saveItem(editedItem.value)" />

    <div class="btn-wrapper">
      <button class="btn" (click)="editable = !editable">Cancel</button>
      <button class="btn btn-save" (click)="saveItem(editedItem.value)">
        Save
      </button>
    </div>
  </div>
</div>
```

 Чекбокс позволяет пользователям отмечать элементы как выполненные.
 Двойные фигурные скобки, `{{}}`, в `<input>` и `<label>` означают Angular-интерполяцию.
 Angular использует `{{item.description}}` для получения описания текущего `item` из массива `items`.
 В следующем разделе подробно объясняется, как компоненты обмениваются данными.

 Следующие две кнопки для редактирования и удаления текущего элемента находятся внутри `<div>`.
 К этому `<div>` применена `*ngIf` — это встроенная Angular-директива, которую вы можете использовать для динамического изменения структуры DOM.

В данном случае `*ngIf` означает, что если `editable` равен `false`, то `<div>` будет присутствовать в DOM. Если `editable` равен `true`, Angular удалит этот `<div>` из DOM.

```html
<div class="btn-wrapper" \*ngIf="!editable">
  <button class="btn" (click)="editable = !editable">Edit</button>
  <button class="btn btn-warn" (click)="remove.emit()">Delete</button>
</div>
```

 Когда пользователь кликает на кнопку **Edit**, `editable` становится true, что удаляет `<div>` и его дочерние элементы из DOM.
 Если вместо клика по кнопке **Edit**, пользователь кликает по кнопке **Delete**, `ItemComponent` вызывает событие, которое уведомляет `AppComponent` об удалении.

 Директива `*ngIf` так же применяется к следующему `<div>`.
 В этом случае, если `editable` равен `true`, Angular вставляет `<div>` и его дочерние элементы `<input>` и `<button>` в DOM.

```html
<!-- Этот блок отображается, если пользователь кликнул на кнопку Edit -->
<div \*ngIf="editable">
  <input
 class="sm-text-input"
 placeholder="edit item"
 [value]="item.description"
 #editedItem
 (keyup.enter)="saveItem(editedItem.value)" />

  <div class="btn-wrapper">
    <button class="btn" (click)="editable = !editable">Cancel</button>
    <button class="btn btn-save" (click)="saveItem(editedItem.value)">
      Save
    </button>
  </div>
</div>
```

 С помощью `[value]="item.description"`, значение `<input>` будет привязано к `description` текущего элемента.
 Эта привязка делает значение `description` значением `<input>`.
 Поэтому если в `description` находится текст `eat`, то он будет автоматически отображён в `<input>`.
 Таким образом, когда пользователь начнёт редактировать элемент, в `<input>` уже будет находится текст `eat`.

 Переменная шаблона `#editedItem` в `<input>` означает, что Angular хранит все, что пользователь печатает в этом `<input>` в переменной `editedItem`.
 Событие `keyup` вызывает метод `saveItem()` и передаёт туда значение из `editedItem`, если пользователь нажмёт Enter вместо кнопки **Save**.

 Когда пользователь нажимает кнопку **Cancel**, `editable` переключается на `false`, что удаляет поле для ввода и кнопки для редактирования из DOM.
 Когда в `editable` находится значение `false`, Angular вставляет `<div>` вместе с кнопками **Edit** и **Delete** обратно в DOM.

 Нажатие на кнопку **Save** вызывает метод `saveItem()`.
 Метод `saveItem()` берёт значение из переменной `#editedItem` `<input>` и изменяет описание элемента `description` на строку `editedItem.value`.

Подготовка AppComponent
-----------------------

 В следующем разделе вы добавите код, который свяжет `AppComponent` и `ItemComponent`.
 Сначала настройте AppComponent, добавив в `app.component.ts`:

```js
remove(item) {
  this.allItems.splice(this.allItems.indexOf(item), 1);
}
```

 Метод `remove()` использует JavaScript-метод `Array.splice()` для удаления одного элемента, начиная с индекса, который возвращает метод `indexOf`.
 Чтобы узнать больше о методе `splice()`, посмотрите статью на MDN `Array.prototype.splice()`.

Добавление логики в ItemComponent
---------------------------------

Чтобы использовать `ItemComponent` вы должны добавить к нему логику и способы ввода/вывода данных.

В `item.component.ts` отредактируйте JavaScript-импорты так:

```js
import { Component, Input, Output, EventEmitter } from "@angular/core";
import { Item } from "../item";
```

`Input`, `Output`, и `EventEmitter` позволяют `ItemComponent` использовать данные совместно с `AppComponent`.
 Импортируя `Item`, `ItemComponent` может понять, что такое `item`.

В `item.component.ts`, замените сгенерированный класс `ItemComponent` следующим:

```js
export class ItemComponent {

  editable = false;

  @Input() item: Item;
  @Input() newItem: string;
  @Output() remove = new EventEmitter<Item>();

  saveItem(description) {
    if (!description) return;
    this.editable = false;
    this.item.description = description;
  }
}
```

 Свойство `editable` помогает переключать раздел шаблона, где пользователь может редактировать элемент.
 `editable` это свойство, которое находится в директиве `*ngIf`: `*ngIf="editable"`.
 Когда вы используете свойство в шаблоне, вы так же должны объявить его в классе.

`@Input()`, `@Output()`, и `EventEmitter` облегчают связь между вашими двумя компонентами.
 `@Input()` служит дверью, через которую данные входят в компонент, а `@Output()` служит дверью для выхода данных.
 `@Output()` должен быть типа `EventEmitter`, чтобы компонент мог вызвать событие, когда данные готовы для отправки в другой компонент.

 Используйте `@Input()`, чтобы указать, что значение свойства может поступать извне.
 Используйте `@Output()` в сочетании с `EventEmitter`, чтобы указать, что свойство может отправить значение в другой компонент.

 Метод `saveItem()` принимает в качестве аргумента `description`.
 `description` это текст, который пользователь вводит в HTML-тэг `<input>` во время редактирования элемента списка.
 `description` это та же строка из `<input>`, полученная через переменную шаблона `#editedItem`.

 Если пользователь не вводит значение, но нажимает **Save**, `saveItem()` ничего не возвращает и не обновляет `description`.
 Если бы выражения `if` не было, пользователь бы нажимал **Save** с пустым `<input>`, и `description` становился бы пустой строкой.

Если пользователь вводит текст и нажимает сохранить, `saveItem()` устанавливает `editable` в false, что заставляет `*ngIf` в шаблоне удалить форму редактирования и отобразить кнопки **Edit** и **Delete** снова.

Несмотря на то что приложение уже должно компилироваться, вам нужно использовать `ItemComponent` в `AppComponent`, чтобы вы могли увидеть новые функции в браузере.

Использование ItemComponent в AppComponent
------------------------------------------

Включение одного компонента в другой в контексте родительско-дочерних отношений даёт вам гибкость в использовании компонентов.

`AppComponent` служит оболочкой для включения других компонентов.

 Чтобы использовать `ItemComponent` в `AppComponent`, вставьте селектор `ItemComponent` в шаблон `AppComponent`.
 В Angular селектор компонента указывается в метаданных декоратора `@Component()`.
 В этом примере селектор это `app-item`:

```js
@Component({
  selector: 'app-item',
  templateUrl: './item.component.html',
  styleUrls: ['./item.component.css']
})
```

 Чтобы использовать селектор `ItemComponent` в `AppComponent`, добавьте элемент `<app-item>`, что соответствует селектору, добавленному в класс компонента, в `app.component.html`.
 Замените текущий неупорядоченный список в `app.component.html` обновлённой версией:

```html
<h2>
  {{items.length}}
  <span \*ngIf="items.length === 1; else elseBlock">item</span>
  <ng-template #elseBlock>items</ng-template>
</h2>

<ul>
  <li \*ngFor="let item of items">
    <app-item (remove)="remove(item)" [item]="item"></app-item>
  </li>
</ul>
```

Двойные фигурные скобки, `{{}}`, в `<h2>` интерполируют длину массива `items` и отображает её.

`<span>` в `<h2>` использует `*ngIf` и `else` чтобы определить, должен ли `<h2>` отображать строку "item" или "items".
 Если в списке всего один элемент, `<span>` будет содержать строку "item".
 В противном случае, если длина массива `items` будет отличаться от `1`, то вместо `<span>` отобразится шаблон `<ng-template>`, который мы назвали `elseBlock` с помощью синтаксиса `#elseBlock`.
 Angular позволяет использовать `<ng-template>`, если вы не хотите, чтобы контент отображался по умолчанию.
 В нашем случае, когда длина массива `items` не `1`, `*ngIf` отображает `elseBlock` а не `<span>`.

`<li>` использует Angular-директиву для повторения,`*ngFor`, чтобы перебрать все элементы массива `items`.
 В Angular `*ngFor` это что-то вроде `*ngIf` - ещё одна директива, которая помогает изменять структуру DOM с помощью меньшего количества кода.
 Для каждого элемента `item`, Angular повторяет `<li>` и всё, что в нём находится, включая `<app-item>`.
 Это означает, что для каждого элемента в массиве Angular создаёт новый экземпляр `<app-item>`.
 Для любого количества элементов в массиве Angular создаёт множество элементов `<li>`.

Вы можете использовать `*ngFor` для других элементов, таких как `<div>`, `<span>` или `<p>` и д.р.

 В `AppComponent` есть метод `remove()` для удаления элемента, связанного со свойством `remove` в `ItemComponent`.
 Свойство `item` в квадратных скобках `[]` связывает значение `item` между `AppComponent` и `ItemComponent`.

 Теперь вы можете редактировать и удалять элементы списка.
 Когда вы добавляете или удаляете элементы, количество элементов так же должно изменятся.
 Чтобы сделать список более удобным, добавьте немного стилей в `ItemComponent`.

Добавление стилей в ItemComponent
---------------------------------

 Вы можете использовать стили, чтобы изменить внешний вид компонента.
 Следующий CSS добавляет базовые стили, flexbox для кнопок и стилизованные чекбоксы.

Вставьте следующе стили в `item.component.css`.

```css
.item {
  padding: 0.5rem 0 0.75rem 0;
  text-align: left;
  font-size: 1.2rem;
}

.btn-wrapper {
  margin-top: 1rem;
  margin-bottom: 0.5rem;
}

.btn {
  /\* flexbox стили для кнопок меню \*/
  flex-basis: 49%;
}

.btn-save {
  background-color: #000;
  color: #fff;
  border-color: #000;
}

.btn-save:hover {
  background-color: #444242;
}

.btn-save:focus {
  background-color: #fff;
  color: #000;
}

.checkbox-wrapper {
  margin: 0.5rem 0;
}

.btn-warn {
  background-color: #b90000;
  color: #fff;
  border-color: #9a0000;
}

.btn-warn:hover {
  background-color: #9a0000;
}

.btn-warn:active {
  background-color: #e30000;
  border-color: #000;
}

.sm-text-input {
  width: 100%;
  padding: 0.5rem;
  border: 2px solid #555;
  display: block;
  box-sizing: border-box;
  font-size: 1rem;
  margin: 1rem 0;
}

/\* Пользовательские чекбоксы
Адаптировано из https://css-tricks.com/the-checkbox-hack/#custom-designed-radio-buttons-and-checkboxes \*/

/\* Основа для стилизации лэйбла \*/
[type="checkbox"]:not(:checked),
[type="checkbox"]:checked {
  position: absolute;
  left: -9999px;
}
[type="checkbox"]:not(:checked) + label,
[type="checkbox"]:checked + label {
  position: relative;
  padding-left: 1.95em;
  cursor: pointer;
}

/\* чекбокс \*/
[type="checkbox"]:not(:checked) + label:before,
[type="checkbox"]:checked + label:before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 1.25em;
  height: 1.25em;
  border: 2px solid #ccc;
  background: #fff;
}

/\* галочка для чекбокса \*/
[type="checkbox"]:not(:checked) + label:after,
[type="checkbox"]:checked + label:after {
  content: "\2713\0020";
  position: absolute;
  top: 0.15em;
  left: 0.22em;
  font-size: 1.3em;
  line-height: 0.8;
  color: #0d8dee;
  transition: all 0.2s;
  font-family: "Lucida Sans Unicode", "Arial Unicode MS", Arial;
}
/\* изменение галочки чекбокса \*/
[type="checkbox"]:not(:checked) + label:after {
  opacity: 0;
  transform: scale(0);
}
[type="checkbox"]:checked + label:after {
  opacity: 1;
  transform: scale(1);
}

/\* доступность \*/
[type="checkbox"]:checked:focus + label:before,
[type="checkbox"]:not(:checked):focus + label:before {
  border: 2px dotted blue;
}
```

Резюме
------

 Теперь у вас должен быть стилизованный Angular-компонент приложения списка дел, позволяющий добавлять, редактировать и удалять элементы.
 Следующий шаг — добавление фильтрации, чтобы можно было просматривать элементы соответствующие определённым критериям.

* Назад
* Обзор: Client-side JavaScript frameworks
* Далее
В это модуле
------------

* Введение в клиентские фреймворки (en-US)
* Основные функции фреймворков (en-US)
* React
    + Начало работы с React
    + Начало создания приложения списка дел с React (en-US)
    + Компоненты React-приложения (en-US)
    + Интерактивность React: события и состояние (en-US)
    + Интерактивность React: редактирование, фильтрация, условная отрисовка (en-US)
    + Доступность в React (en-US)
    + Ресурсы по React (en-US)
* Ember
    + Начало работы с Ember (en-US)
    + Структура Ember-приложения и компоненты (en-US)
    + Интерактивность Ember: события, классы и состояние (en-US)
    + Интерактивность Ember: функциональность подвала, условная отрисовка (en-US)
    + Маршрутизация в Ember (en-US)
    + Ресурсы по Ember и устранение неполадок (en-US)
* Vue
    + Начало работы с Vue (en-US)
    + Создание вашего первого компонента Vue (en-US)
    + Отрисовка списка Vue-компонентов (en-US)
    + Добавление новой формы во Vue: события, методы, и модели (en-US)
    + Стилизация Vue-компонентов с CSS (en-US)
    + Использование вычисляемых свойств во Vue (en-US)
    + Условная отрисовка во Vue: Редактирование существующих дел (en-US)
    + Управление фокусом во Vue с помощью refs (en-US)
    + Ресурсы по Vue (en-US)
* Svelte
    + Начало работы со Svelte (en-US)
    + Начинаем приложение списка дел c использованием Svelte (en-US)
    + Динамическое поведение в Svelte: работа с переменными и пропсами (en-US)
    + Компоненты Svelte-приложения (en-US)
    + Продвинутый Svelte: реактивность, жизненный цикл, доступность (en-US)
    + Работа хранилищами в Svelte (en-US)
    + Поддержка TypeScript в Svelte (en-US)
    + Развёртывание и следующие шаги (en-US)
* Angular
    + Начало работы с Angular
    + Начинаем приложение списка дел с использованием Angular
    + Стилизация Angular-приложения
    + Создание компонента элемента (item component)
    + Фильтрация списка дел
    + Сборка Angular-приложений и другие ресурсы


Начало работы с Angular - Изучение веб-разработки

Начало работы с Angular
=======================

* Назад  (en-US)
* Обзор: Client-side JavaScript frameworks
* Далее

Пришло время взглянуть на фреймворк от Google — Angular, еще один популярный вариант, с которым вы часто будете сталкиваться. В этой статье мы рассмотрим, что Angular может предложить, установим необходимые компоненты, запустим пример приложения, и разберём базовую архитектуру Angular.

| Необходимые условия: | Понимание основ HTML, CSS, и JavaScript, знание терминала/командной строки (en-US). |
| --- | --- |
| Цель: | Настроить локальную среду разработки Angular, создать стартовое приложение, и понять основные принципы работы. |

Что такое Angular?
------------------

Angular — это платформа для разработки, написанная на TypeScript. Как платформа Angular включает:

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

Когда вы создаете приложение с помощью Angular, вы пользуетесь преимуществами платформы, которая может масштабироваться от проекта, который разрабатывает один человек, до приложений корпоративного уровня. Angular разработан, чтобы максимально упростить обновление, поэтому вы можете использовать последние разработки с минимумом усилий. А самое замечательное то, что экосистема Angular состоит из огромного сообщества, включающего более чем 1.7 миллиона разработчиков, авторов библиотек и создателей контента.

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

| `ng build` | Компилирует Angular-приложение в выходной каталог. |
| --- | --- |
| `ng serve` | Собирает и запускает ваше приложение, пересобирая его при изменении файлов. |
| `ng generate` | Генерирует или изменяет файлы на основе схематиков |
| `ng test` | Запускает модульные тесты для заданного проекта. |
| `ng e2e` | Собирает и запускает Angular-приложение, запуская затем сквозные тесты. |

Скоро вы сами убедитесь, что Angular CLI является полезным инструментом для создания ваших приложений.

Что вы создадите
----------------

Эта серия руководств проведёт вас через создание приложения со списком дел (to-do list). С помощью этого приложения вы узнаете, как использовать Angular для управления, редактирования, добавления, удаления и фильтрации элементов.

Необходимые условия
-------------------

Чтобы установить Angular в вашей локальной системе, вам понадобится следующее:

* **Node.js**
 Angular требует текущую, последнюю LTS, или поддерживаемую LTS версию Node.js. Для получения информации о конкретных требованиях к версии смотрите ключ `engines` в package.json файле.
 Для получения дополнительной информации о установке Node.js смотрите nodejs.org.
 Если вы не знаете какая версия Node.js установлена в вашей системе, запустите `node -v` в терминале.
* **пакетный менеджер npm**
 Angular, Angular CLI, Angular приложения зависят от npm пакетов которые обеспечивают множество функций.
 Для загрузки и установки npm пакетов, вам необходим пакетный менеджер npm.
 Это руководство использует npm через интерфейс командной строки, который устанавливается с `Node.js` по умолчанию.
 Для того, чтобы узнать какая версия npm установлена, запустите `npm -v` в терминале.
Настройка приложения
--------------------

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

```js
npm install -g @angular/cli
```

 Команды Angular CLI начинаются с `ng`, за которым следует то, что вы хотите CLI сделал.
 В рабочей директории (например, Desktop) выполните команду `ng new`, чтобы создать новое приложение под названием `todo`:

```js
ng new todo --routing=false --style=css
```

 В текущей директории команда `ng new` создаст необходимое для работы маленькое Angular-приложение.
 Дополнительные флаги, `--routing` и `--style`, определяют, как обрабатывать навигацию и стили в приложении.
 В этом руководстве эти функции будут описаны позже.

Если вам будет предложено применить строгую проверку типов, вы можете ответить "yes".

Перейдите в ваш новый проект с помощью команды `cd`:

```js
cd todo
```

Запустите ваше приложение `todo`, выполнив команду `ng serve`:

```js
ng serve
```

Когда CLI спросить про аналитику, ответьте `no`.

 В браузере перейдите на http://localhost:4200/, и вы увидите ваше новое приложение.
 Если измените любой из исходных файлов, приложение автоматически перезагрузится.

 Пока выполняется `ng serve`, запускать другие команды можно в новой вкладке или окне терминала.
 Если вы захотите остановить работу приложения, нажмите `Ctrl+c` в терминале, где оно было запущено.

Знакомство с вашим Angular приложением
--------------------------------------

 Исходные файлы, на которых будет сосредоточено внимание в этом руководстве находится в `src/app`.
 Файлы, генерируемые CLI автоматически, на которые стоит обратить внимание:

1. `app.module.ts`: определяет файлы, которые использует приложение.
 Этот файл действует как центральный узел для других файлов в вашем приложении.
2. `app.component.ts`: Определяет класс, который содержит логику основной страницы приложения.
3. `app.component.html`: Содержит HTML для `AppComponent`. Содержимое этого файла также называется шаблоном.
 Шаблон определяет представление или то, что вы видите в браузере.
4. `app.component.css`: Содержит стили для `AppComponent`. Этот файл используется, когда вам нужно стилизовать определённый компонент, а не всё приложение.

 Компонент Angular состоит из трех основных частей: шаблон, стили, и класс.
 Например, `app.component.ts`, `app.component.html`, и `app.component.css` вместе составляют `AppComponent`.
 Эта структура разделяет логику, представление и стили, чтобы приложение было более масштабируемым и удобным в обслуживании.

Таким образом, с самого начала вы используете лучшие приёмы разработки.

Angular CLI также генерирует файл для тестирования компонента `app.component.spec.ts`, но в это руководство не входит тестирование, поэтому вы можете игнорировать этот файл.

Каждый раз, когда вы генерируете компонент, CLI создает эти четыре файла в каталоге с указанным вами именем.

Структура Angular приложения
----------------------------

 Angular построен на TypeScript.
 TypeScript — это надмножество JavaScript, т.е. любой правильный JavaScript-код будет работать в TypeScript.
 TypeScript предлагает типизацию и более лаконичный синтаксис, чем простой JavaScript, который дает вам инструмент для создание более удобного в сопровождении кода и минимизации ошибок.

 Компоненты — это строительные блоки Angular-приложений.
 Компоненты включают TypeScript-класс, который имеет декоратор `@Component()`, HTML-шаблон и стили.

### Класс

 Класс — это место, где вы помещаете любую логику, которая нужна вашему компоненту.
 Этот код должен включать функции, обработчики событий, свойства, и ссылки на сервисы.
 Класс находится в файле с таким именем, как `feature.component.ts`, где `feature` это название вашего компонента.
 Итак, у вас могут быть файлы с такими именами как `header.component.ts`, `signup.component.ts`, или `feed.component.ts`.
 Вы создаете компонент с декоратором `@Component()`, включающий метаданные, которые сообщают Angular расположение HTML- и CSS-файлов.
 Типичный компонент выглядит так:

```js
import { Component } from "@angular/core";

@Component({
  selector: "app-item",
  // следующие метаданные определяют расположение других частей компонента
  templateUrl: "./item.component.html",
  styleUrls: ["./item.component.css"],
})
export class ItemComponent {
  // ваш код будет тут
}
```

 Компонент называется `ItemComponent`, и имеет селектор `app-item`.
 Вы можете использовать этот селектор как и обычные HTML-теги, помещая его в другие шаблоны.
 Когда селектор находится в компоненте, браузер отображает шаблон этого компонента.
 Это руководство поможет вам создать два компонента и использовать один в другом.

 Компонентная модель Angular предлагает надежную инкапсуляцию и интуитивно понятную структуру приложения.
 Компоненты также упрощают модульное тестирование вашего приложения и могут улучшить общую читаемость кода.

### HTML-шаблоны

 У каждого компонента есть HTML-шаблон, в котором определяется то, что этот компонент будет отображать.
 Шаблон можно задать либо строкой, либо как путь к файлу.

Для ссылки на внешний HTML-файл, используется свойство `templateUrl`:

```js
@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
})
export class AppComponent {}
```

Чтобы указать напрямую HTML-код, используется свойство `template` с обратными кавычками:

```js
@Component({
  selector: "app-root",
  template: `<h1>Hi!</h1>`,
})
export class AppComponent {}
```

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

```html
<h1>{{ title }}</h1>
```

 Двойные фигурные скобки говорят Angular, что содержимое внутри них нужно интерполировать.
 Значение для `title` берется из класса компонента:

```js
import { Component } from "@angular/core";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
})
export class AppComponent {
  title = "To do application";
}
```

Когда приложение загружает компонент и его шаблон, браузер видит следующее:

```html
<h1>To do application</h1>
```

### Стили

 Компонент может наследовать общие стили приложения из файла `styles.css` или переопределять их собственными стилями.
 Вы можете писать стили для конкретных компонентов прямо в декораторе `@Component()` или указывая путь к CSS-файлу.

Чтобы включить стили непосредственного в декоратор компонента, используется свойство `styles`:

```js
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styles: ['h1 { color: red; }']
})
```

Обычно компонент использует стили определяемые в отельном файле, указанном в свойстве `styleUrls`:

```js
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
```

С помощью стилей для конкретных компонентов вы можете организовывать свой CSS так, чтобы его было легко поддерживать и переносить.

Резюме
------

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

* Назад  (en-US)
* Обзор: Client-side JavaScript frameworks
* Далее
В это модуле
------------

* Введение в клиентские фреймворки (en-US)
* Основные функции фреймворков (en-US)
* React
    + Начало работы с React
    + Начало создания приложения списка дел с React (en-US)
    + Компоненты React приложения (en-US)
    + Интерактивность React: события и состояние (en-US)
    + Интерактивность React: редактирование, фильтрация, условная отрисовка (en-US)
    + Доступность в React (en-US)
    + Ресурсы по React (en-US)
* Ember
    + Начало работы с Ember (en-US)
    + Структура Ember приложения и компоненты (en-US)
    + Интерактивность Ember: события, классы и состояние (en-US)
    + Интерактивность Ember: функциональность подвала, условная отрисовка (en-US)
    + Маршрутизация в Ember (en-US)
    + Ресурсы по Ember и устранение неполадок (en-US)
* Vue
    + Начало работы с Vue (en-US)
    + Создание вашего первого компонента Vue (en-US)
    + Отрисовка списка Vue компонентов (en-US)
    + Добавление новой формы во Vue: события, методы, и модели (en-US)
    + Стилизация Vue компонентов с CSS (en-US)
    + Использование вычисляемых свойств во Vue (en-US)
    + Условная отрисовка во Vue: Редактирование существующих дел (en-US)
    + Управление фокусом во Vue с помощью refs (en-US)
    + Ресурсы по Vue (en-US)
* Svelte
    + Начало работы со Svelte (en-US)
    + Начинаем приложение списка дел c использованием Svelte (en-US)
    + Динамическое поведение в Svelte: работа с переменными и пропсами (en-US)
    + Компоненты Svelte приложения (en-US)
    + Продвинутый Svelte: реактивность, жизненный цикл, доступность (en-US)
    + Работа хранилищами в Svelte (en-US)
    + Поддержка TypeScript в Svelte (en-US)
    + Развертывание и следующие шаги (en-US)
* Angular
    + Начало работы с Angular
    + Начинаем приложение списка дел с использованием Angular
    + Стилизация Angular приложения
    + Создание компонента элемента (item component)
    + Фильтрация списка дел
    + Сборка Angular приложений и другие ресурсы


Начало работы с React - Изучение веб-разработки

Начало работы с React
=====================

* Назад  (en-US)
* Обзор: Client-side JavaScript frameworks
* Далее  (en-US)

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

| Что нужно знать: | HTML, CSS, и JavaScript, быть знакомым с терминалом/командной строкой (en-US).React использует синтаксис HTML-in-JavaScript под названием JSX (JavaScript и XML). Знание HTML и JavaScript поможет вам изучить JSX и лучше определить, связаны ли ошибки в вашем приложении с JavaScript или с более специфической областью React. |
| --- | --- |
| Задача: | Настроить локальную среду разработки React, создать стартовое приложение и понять основы его работы. |

Привет React
------------

Как гласит официальный слоган, React - это библиотека для создания пользовательских интерфейсов. React не является фреймворком – он даже не рассчитан исключительно для web. Он используется для визуализации и в связке с другими библиотеками. Например, React Native можно использовать для создания мобильных приложений; React 360 можно использовать для создания приложений виртуальной реальности; помимо того есть и другие варианты.

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

Основная цель React - минимизировать ошибки, возникающие при разработке пользовательских интерфейсов. Это достигается за счёт использования компонентов - автономных логических фрагментов кода, которые описывают часть пользовательского интерфейса. А уже эти компоненты объединяются для создания полноценного пользовательского интерфейса. React абстрагирует большую часть работы по визуализации, оставляя вам возможность сосредоточиться на дизайне.

Когда использовать
------------------

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

Хотя React *можно* использовать для небольших частей интерфейса, «зайти» в него не так просто, как, к примеру, в jQuery, или даже во Vue. Куда легче это сделать создав всё приложение с помощью React.

Кроме того, такие преимущества React-приложения, как написание интерфейсов с помощью JSX, требуют процесса компиляции. Добавление на сайт компилятора Babel приводит к более медленному выполнению кода, поэтому такие инструменты обычно настраиваются для процесса сборки. Да, возможно, у React есть серьёзные требования к инструментарию, но его можно освоить.

В этой статье основное внимание будет уделено использованию React для создания всего пользовательского интерфейса с помощью create-react-app, предоставляемого Facebook.

Как React использует JavaScript?
--------------------------------

React utilizes features of modern JavaScript for many of its patterns. Its biggest departure from JavaScript comes with the use of JSX syntax. JSX extends JavaScript's syntax so that HTML-like code can live alongside it. For example:

```js
const heading = <h1>Mozilla Developer Network</h1>;
```

This heading constant is known as a **JSX expression**. React can use it to render that `<h1>` tag in our app.

Suppose we wanted to wrap our heading in a `<header>` tag, for semantic reasons? The JSX approach allows us to nest our elements within each other, just like we do with HTML:

```js
const header = (
  <header>
    <h1>Mozilla Developer Network</h1>
  </header>
);
```

**Примечание:** The parentheses in the previous snippet aren't unique to JSX, and don't have any effect on your application. They're a signal to you (and your computer) that the multiple lines of code inside are part of the same expression. You could just as well write the header expression like this:

```jsx
const header = (
  <header>
 <h1>Mozilla Developer Network</h1>
 </header>
);
```

However, this looks kind of awkward, because the `<header>` tag that starts the expression is not indented to the same position as its corresponding closing tag.

Of course, your browser can't read JSX without help. When compiled (using a tool like Babel or Parcel), our header expression would look like this:

```js
const header = React.createElement(
  "header",
  null,
  React.createElement("h1", null, "Mozilla Developer Network"),
);
```

It's *possible* to skip the compilation step and use `React.createElement()` to write your UI yourself. In doing this, however, you lose the declarative benefit of JSX, and your code becomes harder to read. Compilation is an extra step in the development process, but many developers in the React community think that the readability of JSX is worthwhile. Plus, popular tooling makes JSX-to-JavaScript compilation part of its setup process. You don't have to configure compilation yourself unless you want to.

Because JSX is a blend of HTML and JavaScript, some developers find it intuitive. Others say that its blended nature makes it confusing. Once you're comfortable with it, however, it will allow you build user interfaces more quickly and intuitively, and allow others to better understand your code base at a glance.

To read more about JSX, check out the React team's JSX In Depth article.

Настройка вашего первого React приложения
-----------------------------------------

There are many ways to use React, but we're going to use the command-line interface (CLI) tool create-react-app, as mentioned earlier, which expedites the process of developing a React application by installing some packages and creating some files for you, handling the tooling described above.

It's possible to add React to a website without create-react-app by copying some `<script>` elements into an HTML file, but the create-react-app CLI is a common starting point for React applications. Using it will allow you spend more time building your app, and less time fussing with setup.

### Requirements

In order to use create-react-app, you need to have Node.js installed. It's recommended that you use the long-term support (LTS) version. Node includes npm (the node package manager), and npx (the node package runner).

You may also use the Yarn package manager as an alternative, but we'll assume you are using npm in this set of tutorials. See Package management basics (en-US) for more information on npm and yarn.

If you're using Windows, you will need to install some software to give you parity with Unix/macOS terminal in order to use the terminal commands mentioned in this tutorial. **Gitbash** (which comes as part of the git for Windows toolset) or **Windows Subsystem for Linux** (**WSL**) are both suitable. See Command line crash course (en-US) for more information on these, and on terminal commands in general.

Also bear in mind that React and ReactDOM produce apps that only work on a fairly modern set of browsers — IE9+ by way of some polyfills. It is recommended that you use a modern browser like Firefox, Safari, or Chrome when working through these tutorials.

Also see the following for more information:

* "What is npm" on nodejs.org
* "Introducing npx" on the npm blog
* The create-react-app documentation
### Initializing your app

create-react-app takes one argument: the name you'd like to give your app. create-react-app uses this name to make a new directory, then creates the necessary files inside it. Make sure you `cd` to the place you'd like your app to live on your hard drive, then run the following in your terminal:

```bash
npx create-react-app moz-todo-react
```

This creates a `moz-todo-react` directory, and does several things inside it:

* Installs some npm packages essential to the functionality of the app.
* Writes scripts for starting and serving the application.
* Creates a structure of files and directories that define the basic app architecture.
* Initializes the directory as a git repository, if you have git installed on your computer.

**Примечание:** if you have the yarn package manager installed, create-react-app will default to using it instead of npm. If you have both package managers installed and explicitly want to use NPM, you can add the flag `--use-npm` when you run create-react-app:

```bash
npx create-react-app moz-todo-react --use-npm
```

create-react-app will display a number of messages in your terminal while it works; this is normal! This might take a few minutes, so now might be a good time to go make a cup of tea.

When the process is complete, `cd` into the `moz-todo-react` directory and run the command `npm start`. The scripts installed by create-react-app will start being served at a local server at localhost:3000, and open the app in a new browser tab. Your browser will display something like this:

![Screenshot of Firefox MacOS, open to localhost:3000, showing the default create-react-app application](/ru/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started/default-create-react-app.png)

### Application structure

create-react-app gives us everything we need to develop a React application. Its initial file structure looks like this:
```

moz-todo-react
├── README.md
├── node_modules
├── package.json
├── package-lock.json
├── .gitignore
├── public
│   ├── favicon.ico
│   ├── index.html
│   └── manifest.json
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    └── serviceWorker.js
```

The **`src`** directory is where we'll spend most of our time, as it's where the source code for our application lives.

The **`public`** directory contains files that will be read by your browser while you're developing the app; the most important of these is `index.html`. React injects your code into this file so that your browser can run it. There's some other markup that helps create-react-app function, so take care not to edit it unless you know what you're doing. You very much should change the text inside the `<title>` element in this file to reflect the title of your application. Accurate page titles are important for accessibility!

The `public` directory will also be published when you build and deploy a production version of your app. We won't cover deployment in this tutorial, but you should be able to use a similar solution to that described in our Deploying our app (en-US) tutorial.

The `package.json` file contains information about our project that Node.js/npm uses to keep it organized. This file is not unique to React applications; create-react-app merely populates it. You don't need to understand this file at all to complete this tutorial, however, if you'd like to learn more about it, you can read What is the file `package.json`? on NodeJS.org; we also talk about it in our Package management basics (en-US) tutorial.

Изучаем наш первый React компонент — `<App/>`
---------------------------------------------

In React, a **component** is a reusable module that renders a part of our app. These parts can be big or small, but they are usually clearly defined: they serve a single, obvious purpose.

Let's open `src/App.js`, since our browser is prompting us to edit it. This file contains our first component, `App`, and a few other lines of code:

```jsx
import React from "react";
import logo from "./logo.svg";
import "./App.css";

function App() {
  return (
    <div className="App">
 <header className="App-header">
 <img src={logo} className="App-logo" alt="logo" />
 <p>
 Edit <code>src/App.js</code> and save to reload.
 </p>
 <a
 className="App-link"
 href="https://reactjs.org"
 target="\_blank"
 rel="noopener noreferrer">
 Learn React
 </a>
 </header>
 </div>
  );
}
export default App;
```

The `App.js` file consists of three main parts: some `import` statements at the top, the `App` component in the middle, and an `export` statement at the bottom. Most React components follow this pattern.

### Import statements

The `import` statements at the top of the file allow `App.js` to use code that has been defined elsewhere. Let's look at these statements more closely.

```js
import React from "react";
import logo from "./logo.svg";
import "./App.css";
```

The first statement imports the React library itself. Because React turns the JSX we write into `React.createElement()`, all React components must import the `React` module. If you skip this step, your application will produce an error.

The second statement imports a logo from `'./logo.svg'`. Note the `./` at the beginning of the path, and the `.svg` extension at the end — these tell us that the file is local and that it is not a JavaScript file. Indeed, the `logo.svg` file lives in our source directory.

We don't write a path or extension when importing the `React` module — this is not a local file; instead, it is listed as a dependency in our `package.json` file. Be careful of this distinction as you work through this lesson!

The third statement imports the CSS related to our App component. Note that there is no variable name and no `from` directive. This particular import syntax is not native to JavaScript module syntax – it comes from Webpack, the tool create-react-app uses to bundle all our JavaScript files together and serve them to the browser.

### The `App` component

After the imports, we have a function named `App`. Whereas most of the JavaScript community prefers camel-case names like `helloWorld`, React components use pascal-case variable names, like `HelloWorld`, to make it clear that a given JSX element is a React component, and not a regular HTML tag. If you were to rename the `App` function to `app`, your browser would show you an error.

Let's look at App more closely.

```jsx
function App() {
  return (
    <div className="App">
 <header className="App-header">
 <img src={logo} className="App-logo" alt="logo" />
 <p>
 Edit <code>src/App.js</code> and save to reload.
 </p>
 <a
 className="App-link"
 href="https://reactjs.org"
 target="\_blank"
 rel="noopener noreferrer">
 Learn React
 </a>
 </header>
 </div>
  );
}
```

The `App` function returns a JSX expression. This expression defines what your browser ultimately renders to the DOM.

Some elements in the expression have attributes, which are written just like in HTML, following a pattern of `attribute="value"`. On line 3, the opening `<div>` tag has a `className` attribute. This the same as the `class` attribute in HTML, but because JSX is JavaScript, we can't use the word `class` – it's reserved, meaning JavaScript already uses it for a specific purpose and it would cause problems here in our code. A few other HTML attributes are written differently in JSX than they are in HTML too, for the same kind of reason. We'll cover them as we encounter them.

Take a moment to change the `<p>` tag on line 6 so that it reads "Hello, world!", then save your file. You'll notice that this change is immediately rendered in the development server running at `http://localhost:3000` in your browser. Now delete the `<a>` tag and save; the "Learn React" link will be gone.

Your `App` component should now look like this:

```jsx
function App() {
  return (
    <div className="App">
 <header className="App-header">
 <img src={logo} className="App-logo" alt="logo" />
 <p>Hello, World!</p>
 </header>
 </div>
  );
}
```

### Export statements

At the very bottom of the `App.js` file, the statement `export default App` makes our `App` component available to other modules.

Interrogating the index
-----------------------

Let's open `src/index.js`, because that's where the `App` component is being used. This file is the entry point for our app, and it initially looks like this:

```jsx
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import \* as serviceWorker from "./serviceWorker";

ReactDOM.render(<App />, document.getElementById("root"));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
```

As with `App.js`, the file starts by importing all the JS modules and other assets it needs to run. `src/index.css` holds global styles that are applied to our whole app. We can also see our `App` component imported here; it is made available for import thanks to the `export` statement at the bottom of `App.js`.

Line 7 calls React's `ReactDOM.render()` function with two arguments:

* The component we want to render, `<App />` in this case.
* The DOM element inside which we want the component to be rendered, in this case the element with an ID of `root`. If you look inside `public/index.html`, you'll see that this is a `<div>` element just inside the `<body>`.

All of this tells React that we want to render our React application with the `App` component as the root, or first component.

**Примечание:** In JSX, React components and HTML elements must have closing slashes. Writing just `<App>` or just `<img>` will cause an error.

Service workers are interesting pieces of code that help application performance and allow features of your web applications to work offline, but they're not in scope for this article. You can delete line 5, as well as lines 9 through 12.

Your final `index.js` file should look like this:

```jsx
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";

ReactDOM.render(<App />, document.getElementById("root"));
```

Переменные и свойства
---------------------

Next, we'll use a few of our JavaScript skills to get a bit more comfortable editing components and working with data in React. We'll talk about how variables are used inside JSX, and introduce props, which are a way of passing data into a component (which can then be accessed using variables).

### Variables in JSX

Back in `App.js`, let's focus on line 9:

```js
<img src={logo} className="App-logo" alt="logo" />
```

Here, the `<img />` tag's `src` attribute value is in curly braces. This is how JSX recognizes variables. React will see `{logo}`, know you are referring to the logo import on line 2 of our app, then retrieve the logo file and render it.

Let's try making a variable of our own. Before the return statement of `App`, add `const subject = 'React';`. Your `App` component should now look like this:

```jsx
function App() {
  const subject = "React";
  return (
    <div className="App">
 <header className="App-header">
 <img src={logo} className="App-logo" alt="logo" />
 <p>Hello, World!</p>
 </header>
 </div>
  );
}
```

Change line 8 to use our `subject` variable instead of the word "world", like this:

```jsx
function App() {
  const subject = "React";
  return (
    <div className="App">
 <header className="App-header">
 <img src={logo} className="App-logo" alt="logo" />
 <p>Hello, {subject}!</p>
 </header>
 </div>
  );
}
```

When you save, your browser should display "Hello, React!" instead of "Hello, world!"

Variables are convenient, but the one we've just set doesn't make great use of React's features. That's where props come in.

### Component props

A **prop** is any data passed into a React component. Props are written inside component calls, and use the same syntax as HTML attributes — `prop="value"`. Let's open `index.js` and give our `<App/>` call its first prop.

Add a prop of `subject` to the `<App/>` component call, with a value of `Clarice`. When you are done, your code should look something like this:

```jsx
ReactDOM.render(<App subject="Clarice" />, document.getElementById("root"));
```

Back in `App.js`, let's revisit the App function itself, which reads like this (with the `return` statement shortened for brevity):

```js
function App() {
  const subject = "React";
  return (
    // return statement
  );
}
```

Change the signature of the `App` function so that it accepts `props` as a parameter. Just like any other parameter, you can put `props` in a `console.log()` to read it out to your browser's console. Go ahead and do that after your `subject` constant but before the `return` statement, like so:

```js
function App(props) {
  const subject = "React";
  console.log(props);
  return (
    // return statement
  );
}
```

Save your file and check your browser's JavaScript console. You should see something like this logged:

```js
Object { subject: "Clarice" }
```

The object property `subject` corresponds to the `subject` prop we added to our `<App />` component call, and the string `Clarice` corresponds to its value. Component props in React are always collected into objects in this fashion.

Now that `subject` is one of our props, let's utilize it in `App.js`. Change the `subject` constant so that, instead of defining it as the string `React`, you are reading the value of `props.subject`. You can also delete your `console.log()` if you want.

```js
function App(props) {
  const subject = props.subject;
  return (
    // return statement
  );
}
```

When you save, the the app should now greet you with "Hello, Clarice!". If you return to `index.js`, edit the value of `subject`, and save, your text will change.

Резюме
------

This brings us to the end of our initial look at React, including how to install it locally, creating a starter app, and how the basics work. In the next article we'll start building our first proper application — a todo list. Before we do that, however, let's recap some of the things we've learned.

In React:

* Components can import modules they need, and must export themselves at the bottom of their files.
* Component functions are named with `PascalCase`.
* You can read JSX variables by putting them between curly braces, like `{so}`.
* Some JSX attributes are different to HTML attributes, so that they don't conflict with JavaScript reserved words. For example, `class` in HTML translates to `className` in JSX. Note that multi-word attributes are camel-cased.
* Props are written just like attributes inside component calls, and are passed into components.
* Назад  (en-US)
* Обзор: Client-side JavaScript frameworks
* Далее  (en-US)


Фильтрация списка дел - Изучение веб-разработки

Фильтрация списка дел
=====================

* Назад
* Обзор: Client-side JavaScript frameworks
* Далее

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

|  |  |
| --- | --- |
| Необходимые условия: | Понимание основ HTML, CSS, и JavaScript, знание терминала/командной строки (en-US) |
| Цель: | Добавить функционал фильтрации к вашему приложению. |

Код фильтрации
--------------

Фильтрация элементов основана на свойстве `filter`, которое вы ранее добавили в `app.component.ts`:

```js
filter: 'all' | 'active' | 'done' = 'all';
```

Значение фильтра по умолчанию — `all`, но так же может быть `active` или `done`.

Добавление элементов управления фильтром
----------------------------------------

 В `app.component.html`, добавьте следующий html перед кнопкой **Add** но над разделом, в котором перечислены элементы.
 В следующем снипете существующие секции в вашем HTML отмечены комментарии поэтому вы точно можете видеть где разместить кнопки.

```html
<!-- <button class="btn-primary" (click)="addItem(newItem.value)">Add</button>
 -->

<!-- Кнопки, которые меняют отображение элементов на все, только активные или только выполненные -->
<div class="btn-wrapper">
  <button
 class="btn btn-menu"
 [class.active]="filter == 'all'"
 (click)="filter = 'all'">
    All
  </button>

  <button
 class="btn btn-menu"
 [class.active]="filter == 'active'"
 (click)="filter = 'active'">
    To Do
  </button>

  <button
 class="btn btn-menu"
 [class.active]="filter == 'done'"
 (click)="filter = 'done'">
    Done
  </button>
</div>

<!-- <h2>{{items.length}} item(s)</h2>
 <ul>... -->
```

Нажатие на кнопки изменяет значение `filter`, что определяет отображаемые элементы `items`, а так же стили, применяемые к активной кнопке.

* Если пользователь нажимает кнопку **All**, то отображаются все элементы.
* Если пользователь нажимает кнопку **To do**, только элементы со значением свойства `done` равным `false` отображаются.
* Если пользователь нажимает кнопку **Done**, только элементы со значением свойства `done` равным `true` отображаются.

 Привязка атрибута class, которая происходит с использованием квадратных скобок `[]`, управляет цветом текста кнопок.
 Привязка `[class.active]`, применяет класс `active` когда значение `filter` совпадает с выражением.
 Например, когда пользователь нажимает кнопку **Done**, которая устанавливает значение `filter` в `done`, выражение привязки класса `filter == 'done'` возвращает `true`.
 Когда значение `filter` равно `done`, Angular применяет класс `active` к кнопке **Done**, что делает цвет текста зеленым.
 Как только пользователь нажимает одну из других кнопок, значение `filter` больше не `done`, поэтому цвет текста больше не зеленый.

Резюме
------

Это было быстро! Поскольку у вас уже был частично реализован код фильтрации в `app.component.ts`, все что вам нужно было сделать — это отредактировать шаблон, чтобы добавить элементы управления для фильтрации. В следующей и последней статье рассматривается, как создать полностью готовое Angular-приложение и предоставляются дополнительные ресурсы для продолжения учебного пути.

* Назад
* Обзор: Client-side JavaScript frameworks
* Далее
В это модуле
------------

* Введение в клиентские фреймворки (en-US)
* Основные функции фреймворков (en-US)
* React
    + Начало работы с React
    + Начало создания приложения списка дел с React (en-US)
    + Компоненты React-приложения (en-US)
    + Интерактивность React: события и состояние (en-US)
    + Интерактивность React: редактирование, фильтрация, условная отрисовка (en-US)
    + Доступность в React (en-US)
    + Ресурсы по React (en-US)
* Ember
    + Начало работы с Ember (en-US)
    + Структура Ember-приложения и компоненты (en-US)
    + Интерактивность Ember: события, классы и состояние (en-US)
    + Интерактивность Ember: функциональность подвала, условная отрисовка (en-US)
    + Маршрутизация в Ember (en-US)
    + Ресурсы по Ember и устранение неполадок (en-US)
* Vue
    + Начало работы с Vue (en-US)
    + Создание вашего первого компонента Vue (en-US)
    + Отрисовка списка Vue-компонентов (en-US)
    + Добавление новой формы во Vue: события, методы, и модели (en-US)
    + Стилизация Vue-компонентов с CSS (en-US)
    + Использование вычисляемых свойств во Vue (en-US)
    + Условная отрисовка во Vue: Редактирование существующих дел (en-US)
    + Управление фокусом во Vue с помощью refs (en-US)
    + Ресурсы по Vue (en-US)
* Svelte
    + Начало работы со Svelte (en-US)
    + Начинаем приложение списка дел c использованием Svelte (en-US)
    + Динамическое поведение в Svelte: работа с переменными и пропсами (en-US)
    + Компоненты Svelte-приложения (en-US)
    + Продвинутый Svelte: реактивность, жизненный цикл, доступность (en-US)
    + Работа хранилищами в Svelte (en-US)
    + Поддержка TypeScript в Svelte (en-US)
    + Развёртывание и следующие шаги (en-US)
* Angular
    + Начало работы с Angular
    + Начинаем приложение списка дел с использованием Angular
    + Стилизация Angular-приложения
    + Создание компонента элемента (item component)
    + Фильтрация списка дел
    + Сборка Angular-приложений и другие ресурсы


Начинаем приложение списка дел с использованием Angular - Изучение веб-разработки

Начинаем приложение списка дел с использованием Angular
=======================================================

* Назад
* Обзор: Client-side JavaScript frameworks
* Далее

Сейчас мы готовы приступить к созданию приложения списка дел с использованием Angular. Готовое приложение будет отображать список дел, позволять редактировать, удалять и добавлять элементы. В этой статье вы познакомитесь со структурой приложения и поработаете над базовым отображением списка дел.

| Необходимые условия: | Понимание основ HTML, CSS, и JavaScript, знание терминала/командной строки (en-US). |
| --- | --- |
| Цель: | Создать базовую структуру приложения, сделать так, чтобы оно отображало список дел, и понять фундаментальные концепции Angular: структуру компонентов, совместное использование данных между компонентами и использование циклов вывода данных. |

Структура приложения списка дел
-------------------------------

 Как и в приложении без фреймворка, в Angular-приложении есть `index.html`.
 Тэг `<body>` в `index.html`, содержит специальный Angular-элемент — `<app-root>` — для вставки вашего основного компонента, который включает в себя другие компоненты, которые вы создаете.
 Обычно, вам не нужно работать с `index.html`, вместо этого сфокусируйтесь на работе со специальными элементами вашего приложения — компонентами.

### Организация приложения с помощью компонентов

Компоненты — это основной структурный элемент Angular-приложений. Приложение со списком дел состоит из двух компонентов — компонента-основы для вашего приложения и компонента для обработки элементов списка дел.

Каждый компонент состоит из класса TypeScript, HTML и CSS. TypeScript транспилируется в JavaScript — это означает, что ваше приложение в конечном итоге преобразуется в JavaScript, но вы можете использовать расширенные функции Typescript и оптимизированный синтаксис.

### Динамическое изменение UI с помощью \*ngIf и \*ngFor

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

 Первая директива, рассматриваемая в этом руководстве — это Angular-итератор, `*ngFor`.
 `*ngFor` дает возможность динамически создавать DOM-элементы на основе элементов массива.

 Вторая директива, которую вы изучите в этом руководстве — это `*ngIf`.
 Вы можете использовать `*ngIf` для добавления или удаления элементов из DOM в зависимости от условия.
 Например, если пользователи хотят отредактировать элемент в списке дел, вы можете предоставить им средства для редактирования этого элемента.
 Если они не хотят редактировать элемент, вы можете удалить элементы для редактирования.

### Обмен данными между компонентами

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

 Обмен данными между Angular-компонентами происходит с помощью специальных декораторов, называемых `@Input()` и `@Output()`.
 Эти декораторы указывают, что определенные свойства могут получать или отправлять данные. Использование `@Output()` означает, что вы вызываете событие в одном компоненте, чтобы оповестить другой компонент об изменении данных.

Определение элемента
--------------------

В директории `app`, создайте новый файл и назовите его `item.ts`, затем поместите туда следующее:

```js
export interface Item {
  description: string;
  done: boolean;
}
```

`Item` как `interface` описывает `item` как объект, чтобы приложение могло понимать, что такое `item` и как с ним взаимодействовать.
 Для нашего списка дел, `item` это объект у которого есть описание (description) и он может быть выполнен (done).

Добавление логики в AppComponent
--------------------------------

 Теперь, когда выше приложение знает, что такое `item`, вы можете добавить несколько элементов в `app.component.ts`.
 В `app.component.ts` замените содержимое на:

```js
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  title = 'todo';

  filter: 'all' | 'active' | 'done' = 'all';

  allItems = [
    { description: 'eat', done: true },
    { description: 'sleep', done: false },
    { description: 'play', done: false },
    { description: 'laugh', done: false },
  ];

  get items() {
    if (this.filter === 'all') {
      return this.allItems;
    }
    return this.allItems.filter(item => this.filter === 'done' ? item.done : !item.done);
  }

}
```

 Первая строка — это импорт JavaScript, который импортирует Angular .
 `@Component()` декоратор описывает метаданные `AppComponent`.
 Свойства метаданных по умолчанию следующие:

* `selector`: Сообщает имя селектора CSS, который используется в шаблоне для создания экземпляра этого компонента. Тут это `'app-root'`.
 В `index.html` внутри тэга `body`, Angular CLI добавляет `<app-root></app-root>` когда генерирует приложение.
 Вы можете использовать селекторы компонентов точно так же, добавляя их к другим HTML-шаблонам компонентов.
* `templateUrl`: Задает HTML-файл, который нужно связать с этим компонентом. .
 Тут это './app.component.html',
* `styleUrls`: Предоставляет расположение и имя файла для стилей, которые применяются конкретно к этому компоненту. Тут это `'./app.component.css'`.

 Свойство `filter` имеет тип `union`, это значит, что `filter` может принимать значения: `all`, `active` или `done`.
 С типом `union`, если вы опечатаетесь в значении, которое присваиваете свойству `filter`, TypeScript сообщит об этом, чтобы вы могли вовремя отловить ошибку.
 В этом руководстве показано, как добавить фильтрацию на более позднем этапе, но вы также можете использовать фильтр, чтобы отобразить список всех элементов по умолчанию.

 Массив `allItems` содержит текущие дела, в том числе и выполненные (`done`).
 Первый элемент, `eat`, имеет значение свойства `done: true`.

 Геттер, `get items()`, извлекает все элементы из массива `allItems` если `filter` имеет значение `all`.
 Иначе, `get items()` возвращает завершенные (`done: true`) или незавершенные (`done: false`) элементы в зависимости от того, как пользователь фильтрует представление.
 Геттер так же устанавливает `items` как имя массива, которое вы будете использовать в следующем блоке.

Добавление HTML-шаблона для AppComponent
----------------------------------------

Чтобы увидеть список элементов в браузере, замените содержимое `app.component.html` на следующий HTML:

```html
<div class="main">
  <h1>My To Do List</h1>
  <h2>What would you like to do today?</h2>

  <ul>
    <li \*ngFor="let item of items">{{item.description}}</li>
  </ul>
</div>
```

 Тэг `<li>` содержит `*ngFor` — встроенную директива Angular, которая перебирает элементы в массиве `items`.
 Для каждого элемента, `*ngFor` создает новый тэг `<li>`.
 Двойные фигурные скобки, которые содержат `item.description` сообщают Angular, что нужно заполнить каждый тэг `<li>` текстом из item's description.

В браузере вы должны увидеть список элементов:
```

My To Do List
What would you like to do today?

* eat
* sleep
* play
* laugh
```

Добавление элементов в список
-----------------------------

С список дел нужно добавлять элементы.

Добавьте в `app.component.ts`, следующий метод класса:

```js
addItem(description: string) {
  this.allItems.unshift({
    description,
    done: false
  });
}
```

 Метод `addItem()` принимает элемент, который предоставляет пользователь, и добавляет его в массив, когда пользователь нажимает кнопку **Add**. `addItem()` использует метод массива `unshift()` чтобы добавить новый элемент в начало массива и, соответственно, начало списка.
 Вы можете использовать метод `push()`, который добавит новый элемент в конец массива и, соответственно, конец списка.

Для того, чтобы использовать метод `addItem()`, отредактируйте HTML в шаблоне `AppComponent`.

В `app.component.html`, замените `<h2>` на следующее:

```js
<label for="addItemInput">What would you like to do today?</label>

<input
  #newItem
  placeholder="add an item"
  (keyup.enter)="addItem(newItem.value); newItem.value = ''"
  class="lg-text-input"
  id="addItemInput"
/>

<button class="btn-primary" (click)="addItem(newItem.value)">Add</button>
```

 Когда пользователь вводит новый элемент в `<input>` и нажимает **Enter**, метод `addItem()` добавляет значение в массив `items`.
 Нажатие **Enter** так же сбрасывает значение в `<input>` на пустую строку.
 В качестве альтернативы пользователь может щелкнуть на кнопке **Add**, которая так же вызовет метод `addItem()`.

Резюме
------

Сейчас у вас должен быть список дел, отображаемый в вашем браузере. Это большой прогресс! Конечно, нам предстоит еще многое сделать. В следующей статье мы рассмотрим добавление стилей в наше приложение.

* Назад
* Обзор: Client-side JavaScript frameworks
* Далее
В это модуле
------------

* Введение в клиентские фреймворки (en-US)
* Основные функции фреймворков (en-US)
* React
    + Начало работы с React
    + Начало создания приложения списка дел с React (en-US)
    + Компоненты React приложения (en-US)
    + Интерактивность React: события и состояние (en-US)
    + Интерактивность React: редактирование, фильтрация, условная отрисовка (en-US)
    + Доступность в React (en-US)
    + Ресурсы по React (en-US)
* Ember
    + Начало работы с Ember (en-US)
    + Структура Ember приложения и компоненты (en-US)
    + Интерактивность Ember: события, классы и состояние (en-US)
    + Интерактивность Ember: функциональность подвала, условная отрисовка (en-US)
    + Маршрутизация в Ember (en-US)
    + Ресурсы по Ember и устранение неполадок (en-US)
* Vue
    + Начало работы с Vue (en-US)
    + Создание вашего первого компонента Vue (en-US)
    + Отрисовка списка Vue компонентов (en-US)
    + Добавление новой формы во Vue: события, методы, и модели (en-US)
    + Стилизация Vue компонентов с CSS (en-US)
    + Использование вычисляемых свойств во Vue (en-US)
    + Условная отрисовка во Vue: Редактирование существующих дел (en-US)
    + Управление фокусом во Vue с помощью refs (en-US)
    + Ресурсы по Vue (en-US)
* Svelte
    + Начало работы со Svelte (en-US)
    + Начинаем приложение списка дел c использованием Svelte (en-US)
    + Динамическое поведение в Svelte: работа с переменными и пропсами (en-US)
    + Компоненты Svelte приложения (en-US)
    + Продвинутый Svelte: реактивность, жизненный цикл, доступность (en-US)
    + Работа хранилищами в Svelte (en-US)
    + Поддержка TypeScript в Svelte (en-US)
    + Развертывание и следующие шаги (en-US)
* Angular
    + Начало работы с Angular
    + Начинаем приложение списка дел с использованием Angular
    + Стилизация Angular приложения
    + Создание компонента элемента (item component)
    + Фильтрация списка дел
    + Сборка Angular приложений и другие ресурсы


Сборка Angular приложений и другие ресурсы - Изучение веб-разработки

Сборка Angular приложений и другие ресурсы
==========================================

* Назад
* Обзор: Client-side JavaScript frameworks

В финальной статье об Angular рассказывается, как создать полностью готовое приложение и предоставляются дополнительные ресурсы, которые помогут вам продолжить обучение

|  |  |
| --- | --- |
| Необходимые условия: | Понимание основ HTML, CSS, и JavaScript, знание терминала/командной строки (en-US) |
| Цель: | Изучить сборку Angular-приложения. |

Сборка законченного приложения
------------------------------

 Теперь, когда вы закончили разработку своего приложения, вы можете запустить команду Angular CLI `build`.
 Когда вы запускаете команду `build` в директории `todo`, ваше приложение компилируется в директорию с названием `dist/`.

В директории `todo`, выполните следующие команды:

```bash
ng  build --prod
```

 CLI компилирует приложение и помещает результат в директорию `dist`.
 Флаг `--prod` команды `ng build` избавляется от всего, что вам не нужно в продакшене.

Развертывание вашего прилоежния
-------------------------------

 Для развертывания вашего приложения вы можете скопировать содержимое папки `dist/my-project-name` на ваш веб-сервер.
 Поскольку это статичные файлы, вы можете разместить на любом веб-сервере способном обслуживать файлы, например:

* Node.js
* Java
* .NET

Вы можете использовать любой бэкэнд, например Firebase, Google Cloud, или App Engine.

Что дальше
----------

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

* Tour of Heroes: подробное руководство, в котором рассматриваются функции Angular, такие как использование сервисов, навигация и получение данных с сервера.
* Руководство по Angular-компонентам: серия статей по таким темам как жизненный цикл, взаимодействие компонентов и инкапсуляция представлений.
* Руководство по формам: статьи, которые проведут вас через создание реактивных форм в Angular, проверку ввода и построения динамических форм.
Резюме
------

На этом пока все. Надеемся, вам понравилось работать с Angular!

* Назад
* Обзор: Client-side JavaScript frameworks
В это модуле
------------

* Введение в клиентские фреймворки (en-US)
* Основные функции фреймворков (en-US)
* React
    + Начало работы с React
    + Начало создания приложения списка дел с React (en-US)
    + Компоненты React-приложения (en-US)
    + Интерактивность React: события и состояние (en-US)
    + Интерактивность React: редактирование, фильтрация, условная отрисовка (en-US)
    + Доступность в React (en-US)
    + Ресурсы по React (en-US)
* Ember
    + Начало работы с Ember (en-US)
    + Структура Ember-приложения и компоненты (en-US)
    + Интерактивность Ember: события, классы и состояние (en-US)
    + Интерактивность Ember: функциональность подвала, условная отрисовка (en-US)
    + Маршрутизация в Ember (en-US)
    + Ресурсы по Ember и устранение неполадок (en-US)
* Vue
    + Начало работы с Vue (en-US)
    + Создание вашего первого компонента Vue (en-US)
    + Отрисовка списка Vue-компонентов (en-US)
    + Добавление новой формы во Vue: события, методы, и модели (en-US)
    + Стилизация Vue-компонентов с CSS (en-US)
    + Использование вычисляемых свойств во Vue (en-US)
    + Условная отрисовка во Vue: Редактирование существующих дел (en-US)
    + Управление фокусом во Vue с помощью refs (en-US)
    + Ресурсы по Vue (en-US)
* Svelte
    + Начало работы со Svelte (en-US)
    + Начинаем приложение списка дел c использованием Svelte (en-US)
    + Динамическое поведение в Svelte: работа с переменными и пропсами (en-US)
    + Компоненты Svelte-приложения (en-US)
    + Продвинутый Svelte: реактивность, жизненный цикл, доступность (en-US)
    + Работа хранилищами в Svelte (en-US)
    + Поддержка TypeScript в Svelte (en-US)
    + Развёртывание и следующие шаги (en-US)
* Angular
    + Начало работы с Angular
    + Начинаем приложение списка дел с использованием Angular
    + Стилизация Angular-приложения
    + Создание компонента элемента (item component)
    + Фильтрация списка дел
    + Сборка Angular-приложений и другие ресурсы


Стилизация вашего Angular-приложения - Изучение веб-разработки

Стилизация вашего Angular-приложения
====================================

* Назад
* Обзор: Client-side JavaScript frameworks
* Далее

Теперь, когда мы создали базовую структуру приложения и начали отображать что-то полезное, давайте переключимся и рассмотрим статью, посвященную тому, как Angular работает со стилями.

|  |  |
| --- | --- |
| Необходимые условия: | Понимание основ HTML, CSS, и JavaScript, знание терминала/командной строки (en-US) |
| Цель: | Изучить, как работать со стилями в Angular. |

Добавление стилей
-----------------

Angular CLI генерирует файлы стилей двух типов:

* Стили компонентов: Angular CLI создает для каждого компонента файл с его стилями.
 Стили в этом файле применяются только к этому компоненту.
* `styles.css`: В дирректории `src`, стили в этом файле применяются ко всему приложению, если не будут указаны стили на уровне компонента.

 Если вы используете препроцессоры, расширение файлов со стилями может различаться.
 Кроме обычного CSS Angular поддерживает SCSS, Sass, Less и Stylus.

Вставьте в `src/styles.css` следующие стили:

```css
body {
  font-family: Helvetica, Arial, sans-serif;
}

.btn-wrapper {
  /\* flexbox \*/
  display: flex;
  flex-wrap: nowrap;
  justify-content: space-between;
}

.btn {
  color: #000;
  background-color: #fff;
  border: 2px solid #cecece;
  padding: 0.35rem 1rem 0.25rem 1rem;
  font-size: 1rem;
}

.btn:hover {
  background-color: #ecf2fd;
}

.btn:active {
  background-color: #d1e0fe;
}

.btn:focus {
  outline: none;
  border: black solid 2px;
}

.btn-primary {
  color: #fff;
  background-color: #000;
  width: 100%;
  padding: 0.75rem;
  font-size: 1.3rem;
  border: black solid 2px;
  margin: 1rem 0;
}

.btn-primary:hover {
  background-color: #444242;
}

.btn-primary:focus {
  color: #000;
  outline: none;
  border: #000 solid 2px;
  background-color: #d7ecff;
}

.btn-primary:active {
  background-color: #212020;
}
```

 CSS в `src/styles.css` применяется ко всему приложению, но стилизует лишь некоторые элементы страницы.
 Дальше мы добавим стили конкретно для компонента `AppComponent`.

Для этого в `app.component.css` добавьте следующие стили:

```css
body {
  color: #4d4d4d;
  background-color: #f5f5f5;
  color: #4d4d4d;
}

.main {
  max-width: 500px;
  width: 85%;
  margin: 2rem auto;
  padding: 1rem;
  text-align: center;
  box-shadow:
    0 2px 4px 0 rgba(0, 0, 0, 0.2),
    0 2.5rem 5rem 0 rgba(0, 0, 0, 0.1);
}

@media screen and (min-width: 600px) {
  .main {
    width: 70%;
  }
}

label {
  font-size: 1.5rem;
  font-weight: bold;
  display: block;
  padding-bottom: 1rem;
}

.lg-text-input {
  width: 100%;
  padding: 1rem;
  border: 2px solid #000;
  display: block;
  box-sizing: border-box;
  font-size: 1rem;
}

.btn-wrapper {
  margin-bottom: 2rem;
}

.btn-menu {
  flex-basis: 32%;
}

.active {
  color: green;
}

ul {
  padding-inline-start: 0;
}

ul li {
  list-style: none;
}
```

После можно вернуться в браузер и посмотреть, как обновились стили. Теперь все стало немного понятнее.

Резюме
------

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

* Назад
* Обзор: Client-side JavaScript frameworks
* Далее
В это модуле
------------

* Введение в клиентские фреймворки (en-US)
* Основные функции фреймворков (en-US)
* React
    + Начало работы с React
    + Начало создания приложения списка дел с React (en-US)
    + Компоненты React приложения (en-US)
    + Интерактивность React: события и состояние (en-US)
    + Интерактивность React: редактирование, фильтрация, условная отрисовка (en-US)
    + Доступность в React (en-US)
    + Ресурсы по React (en-US)
* Ember
    + Начало работы с Ember (en-US)
    + Структура Ember приложения и компоненты (en-US)
    + Интерактивность Ember: события, классы и состояние (en-US)
    + Интерактивность Ember: функциональность подвала, условная отрисовка (en-US)
    + Маршрутизация в Ember (en-US)
    + Ресурсы по Ember и устранение неполадок (en-US)
* Vue
    + Начало работы с Vue (en-US)
    + Создание вашего первого компонента Vue (en-US)
    + Отрисовка списка Vue компонентов (en-US)
    + Добавление новой формы во Vue: события, методы, и модели (en-US)
    + Стилизация Vue компонентов с CSS (en-US)
    + Использование вычисляемых свойств во Vue (en-US)
    + Условная отрисовка во Vue: Редактирование существующих дел (en-US)
    + Управление фокусом во Vue с помощью refs (en-US)
    + Ресурсы по Vue (en-US)
* Svelte
    + Начало работы со Svelte (en-US)
    + Начинаем приложение списка дел c использованием Svelte (en-US)
    + Динамическое поведение в Svelte: работа с переменными и пропсами (en-US)
    + Компоненты Svelte приложения (en-US)
    + Продвинутый Svelte: реактивность, жизненный цикл, доступность (en-US)
    + Работа хранилищами в Svelte (en-US)
    + Поддержка TypeScript в Svelte (en-US)
    + Развертывание и следующие шаги (en-US)
* Angular
    + Начало работы с Angular
    + Начинаем приложение списка дел с использованием Angular
    + Стилизация Angular приложения
    + Создание компонента элемента (item component)
    + Фильтрация списка дел
    + Сборка Angular приложений и другие ресурсы


Реализация функции обнаружения - Изучение веб-разработки

Реализация функции обнаружения
==============================

* Назад  (en-US)
* Обзор: Cross browser testing
* Далее  (en-US)

Обнаружение функций включает определение того, поддерживает ли браузер определённый блок кода, и выполнение другого кода в зависимости от того, поддерживает ли он или нет, так что браузер всегда может обеспечить работу, а не сбой / ошибку в некоторых браузерах. В этой статье подробно описывается, как написать собственное простое обнаружение функций, как использовать библиотеку для ускорения реализации, а также встроенные функции для обнаружения функций, такие как `@supports`.

| Предусловия: | Знакомство с основными языками HTML, CSS, и JavaScript; идея высокого уровня принципов кросс-браузерного тестирования.. |
| --- | --- |
| Задача: | Понять, что такое концепция выявления функций, и уметь внедрять подходящие решения в CSS и JavaScript. |

Концепция обнаружения функций
-----------------------------

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

Давайте подведём итоги и посмотрим на пример, который мы затронули в нашем документе Решение самых распространённых проблем JavaScript (en-US)— Использование геолокации (который предоставляет доступные данные о местоположении для устройства, на котором работает веб-браузер) есть основная точка входа для его использования, свойство `geolocation,` доступное на глобальном объекте Navigator. Следовательно, вы можете определить, поддерживает ли браузер геолокацию или нет, используя что-то вроде следующего:

```js
if ("geolocation" in navigator) {
  navigator.geolocation.getCurrentPosition(function (position) {
    // show the location on a map, perhaps using the Google Maps API
  });
} else {
  // Give the user a choice of static maps instead perhaps
}
```

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

Прежде чем мы продолжим, мы хотели бы сразу сказать одну вещь - не путайте обнаружение функций с **перехватом браузера** (обнаружение того, какой конкретный браузер обращается к сайту) - это ужасная практика, от которой следует отказаться любой ценой. См. Использование плохого кода перехвата браузера (en-US) для дополнительной информации.

Написание ваших собственных тестов обнаружения функций
------------------------------------------------------

В этом разделе мы рассмотрим реализацию ваших собственных тестов обнаружения функций как в CSS, так и в JavaScript.

### CSS

Вы можете написать тесты для функций CSS, протестировав существование *element.style.property (en-US)* (например, `paragraph.style.transform`) в JavaScript.

Классическим примером может быть проверка поддержки Flexbox в браузере; для браузеров, которые поддерживают новейшие спецификации Flexbox, мы могли бы использовать гибкую и надёжную гибкую компоновку. Для браузеров, которые этого не делают, мы могли бы использовать плавающий макет, который работает нормально, хотя он немного более хрупкий и хакерский, и не такой привлекательный.

Давайте реализуем что-то, что демонстрирует это, хотя мы пока оставим это простым.

1. Начните с создания локальных копий наших файлов `css-feature-detect.html`, `flex-layout.css`, `float-layout-css`, и `basic-styling.css`. Сохраните их в новой дирекции.
2. Мы добавим HTML5 Shiv и в наш пример, чтобы семантические элементы HTML5 правильно стилизовались в старых версиях IE. Загрузите последнюю версию (См. Ручная установка), разархивируйте ZIP, скопируйте файлы `html5shiv-printshiv.min.js` и `html5shiv.min.js` в ваш пример дирекции и создайте ссылку на один из файлов, поместив следующее в свой `<title>` элемент:
```

<script src="html5shiv.min.js"></script>
```

3. Посмотрите ваши примеры CSS-файлов - вы увидите, что `basic-styling.css` обрабатывает все стили, которые мы хотим дать каждому браузеру, тогда как два других CSS-файла содержат CSS, который мы хотим выборочно применять к браузеру в зависимости от их уровни поддержки. Вы можете посмотреть на различные эффекты этих двух файлов, вручную изменив CSS-файл, на который ссылается второй элемент `<link>`, но давайте вместо этого реализуем некоторый JavaScript, чтобы автоматически заменять их при необходимости.
4. Сначала удалите содержимое атрибута `href` второго элемента `<link>` . Мы будем заполнять это динамически позже.
5. Затем добавьте элемент `<script></script>` внизу вашего контекста (непосредственно перед закрывающим тегом `</body>`).
6. Дайте ему следующее содержание:

```js
const conditional = document.querySelector(".conditional");
const testElem = document.createElement("div");
if (
  testElem.style.flex !== undefined &&
  testElem.style.flexFlow !== undefined
) {
  conditional.setAttribute("href", "flex-layout.css");
} else {
  conditional.setAttribute("href", "float-layout.css");
}
```

Здесь мы берём ссылку на второй элемент `<link>` и создаём элемент `<div>` как часть нашего теста. В нашем условном выражении мы проверяем, что свойства `flex` и `flex-flow` существуют в браузере. Обратите внимание, что представления JavaScript этих свойств, которые хранятся внутри объекта `HTMLElement.style` (en-US), используют нижний горбатый регистр, а не дефисы, для разделения слов.

**Примечание:** Если у вас возникли проблемы с выполнением этого, вы можете сравнить его с нашим кодом css-feature-detect-finished.html (см. Также живую версию).

Когда вы сохраните все и опробуете свой пример, вы должны увидеть макет flexbox, применённый к странице, если браузер поддерживает современный flexbox, и макет float, если нет.

**Примечание:** Часто такой подход является излишним из-за незначительной проблемы с обнаружением функций - вы часто можете обойтись без использования префиксов нескольких поставщиков и свойств резервирования, как описано в разделе Поведение CSS-откат (en-US) и Обработка префиксов CSS (en-US).

#### @supports

Недавно, в CSS появился собственный механизм обнаружения собственных функций — @-правило `@supports`. Это работает аналогично медиавыражениям (см. Также Адаптивные проблемы дизайна (en-US)) — за исключением того, что вместо выборочного применения CSS в зависимости от медиа-функции, такой как разрешение, ширина экрана или соотношение сторон, выборочно применяется CSS в зависимости от того, поддерживается ли функция CSS.

Например, мы могли бы переписать наш предыдущий пример для использования `@supports` — см. `supports-feature-detect.html` и `supports-styling.css`. Если вы посмотрите на последнее, вы увидите пару блоков `@supports` например:

```css
@supports (flex-flow: row) and (flex: 1) {
  main {
    display: flex;
  }

  main div {
    padding-right: 4%;
    flex: 1;
  }

  main div:last-child {
    padding-right: 0;
  }
}
```

Этот блок применяет правило CSS только в том случае, если текущий браузер поддерживает объявления как `flex-flow: row` так и `flex: 1`. Чтобы каждое условие работало, вам необходимо включить полное объявление (а не просто имя свойства) и НЕ включать точку с запятой в конце.

`@supports` также имеет логику `OR` и `NOT` — другой блок применяет разметку с плавающей запятой, если свойства flexbox недоступны:

```css
@supports not (flex-flow: row) and (flex: 1) {
  /\* rules in here \*/
}
```

Это может выглядеть намного удобнее, чем в предыдущем примере - мы можем выполнять все наши функции обнаружения в CSS, JavaScript не требуется, и мы можем обрабатывать всю логику в одном файле CSS, сокращая HTTP-запросы. Проблема здесь в поддержке браузера — `@supports` вообще не поддерживается в IE, а поддерживается только в самых последних версиях Safari / iOS WebKit (9 + / 9.2 +), тогда как версия JavaScript должна работать в гораздо более старых браузерах (вероятно, назад до IE8 или 9, хотя в более старых версиях IE будут возникать дополнительные проблемы, такие как отсутствие поддержки `Document.querySelector` и наличие испорченной блочной модели).

### JavaScript

Мы уже видели пример теста на обнаружение функций JavaScript ранее. Как правило, такие тесты выполняются по одному из следующих общих шаблонов:

| Тип обнаружения функции | Объяснение | Пример |
| --- | --- | --- |
| *Если член в объекте* | Проверьте, существует ли определённый метод или свойство (обычно точка входа в использование API или другой функции, которую вы обнаруживаете) в его родительском объекте. | `if("geolocation" in navigator) { ... }` |
| *Свойство на элементе* | Создайте элемент в памяти, используя `Document.createElement()`, а затем проверьте, существует ли свойство для него. Показанный пример является способом определения поддержки HTML5 Canvas. | `function supports_canvas() { return !!document.createElement('canvas').getContext; } if(supports_canvas()) { ... }` |
| *Метод на возвращаемое значение элемента* | Создайте элемент в памяти, используя `Document.createElement()`, а затем проверьте, существует ли метод для него. Если это так, проверьте, какое значение он возвращает. | См. Dive Into HTML5 Video Formats detection. |
| *Свойство на сохраняемое значение элемента* | Создайте элемент в памяти, используя `Document.createElement()`, установите для свойства определённое значение, затем проверьте, сохраняется ли значение. | См. Dive into HTML5 `<input>` types detection. |

**Примечание:** Двойное `NOT` в приведённом выше примере (`!!`) это способ заставить возвращаемое значение стать «правильным» логическим значением, а не Truthy/Falsy значение, которое может исказить результаты.

Страница Погружение в HTML5 Обнаружение функций HTML5 содержит гораздо больше полезных тестов для обнаружения функций, помимо перечисленных выше, и вы можете найти тест обнаружения функций для большинства вещей, выполнив поиск «обнаружение поддержки для ВАШИ-ФУНКЦИИ-ЗДЕСЬ» в своей любимой поисковой системе. Имейте в виду, однако, что некоторые функции, как известно, не обнаруживаются - см. список Modernizr Необнаруживаемые.

#### matchMedia

Мы также хотели упомянуть функцию JavaScript `Window.matchMedia` на этом этапе. Это свойство, которое позволяет вам запускать тесты медиавыражений внутри JavaScript. Это выглядит так:

```js
if (window.matchMedia("(max-width: 480px)").matches) {
  // run JavaScript in here.
}
```

В качестве примера, наша демо версия Snapshot использует её для выборочного применения библиотеки Brick JavaScript и её использования для обработки макета пользовательского интерфейса, но только для небольшого экрана (шириной 480 пикселей или меньше). Сначала мы используем атрибут `media`,чтобы применить CSS-код Brick к странице, только если ширина страницы составляет 480px или меньше:

```css
<link href="dist/brick.css" type="text/css" rel="stylesheet" media="all and (max-width: 480px)">
```

Затем мы используем `matchMedia()` в JavaScript несколько раз, чтобы запускать функции навигации Brick только в том случае, если мы на маленьком экране (в более широких экранах все можно увидеть сразу, поэтому нам не нужно переходить между различными изображениями).

```js
if (window.matchMedia("(max-width: 480px)").matches) {
  deck.shuffleTo(1);
}
```

Использование Modernizr для реализации обнаружения функций
----------------------------------------------------------

Можно реализовать свои собственные тесты обнаружения функций, используя методы, подобные тем, которые подробно описаны выше. Вы можете также использовать специальную библиотеку обнаружения функций, так как она всё упрощает. Основой всех библиотек обнаружения функций является Modernizr, и он может обнаружить практически все, что вам когда-либо понадобится. Давайте посмотрим, как его использовать.

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

1. Нажав на ссылку Сборка разработки.
2. Нажав на большую розовую кнопку *Build* на появившейся странице.
3. Нажав на верхнюю ссылку *Download* в появившемся диалоговом окне.

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

Когда вы используете Modernizr в рабочей среде, вы можете перейти на Страницу скачивания которую вы уже посетили, и нажимать кнопки плюс только для тех функций, которые вам нужны. Затем, когда вы нажмёте кнопку *Build* вы загрузите пользовательскую сборку, содержащую только те функции, которые обнаружены, что позволит значительно уменьшить размер файла.

### CSS

Давайте посмотрим, как Modernizr работает с точки зрения избирательного применения CSS.

1. Во-первых, создайте копию `supports-feature-detect.html` и `supports-styling.css`. Сохраните их как `modernizr-css.html` и `modernizr-css.css`.
2. Обновите ваш элемент `<link>` в своём HTML-коде, чтобы он указывал на правильный файл CSS (также следует обновить элемент `<title>` на что-то более подходящее!):

```html
<link href="modernizr-css.css" rel="stylesheet" />
```

3. Над этим элементом `<link>` добавьте элемент `<script>`, чтобы применить библиотеку Modernizr к странице, как показано ниже. Это должно быть применено к странице перед любым CSS (или JavaScript), который может её использовать.

```html
<script src="modernizr-custom.js"></script>
```

4. Теперь отредактируйте открывающий тег `<html>`, чтобы он выглядел так:

```html
<html class="no-js"></html>
```

На этом этапе попробуйте загрузить свою страницу, и вы получите представление о том, как Modernizr работает с функциями CSS. Если вы посмотрите на инспектор DOM инструментов разработчика вашего браузера, вы увидите, что Modernizr обновил значение вашего `<html>` `class` следующим образом:
```

<html class="js no-htmlimports sizes flash transferables applicationcache blobconstructor
blob-constructor cookies cors ...AND LOADS MORE VALUES!>
```

Теперь он содержит большое количество классов, которые указывают на состояние поддержки различных функций. Например, если браузер вообще не поддерживает flexbox, `<html>` будет присвоено имя класса `no-flexbox`. Если бы он поддерживал современный flexbox, он получил бы имя класса `flexbox`. Если вы выполните поиск в списке классов, вы также увидите другие, относящиеся к flexbox, например:

* `flexboxlegacy` для старой спецификации flexbox (2009).
* `flexboxtweener` для промежуточного синтаксиса 2011 года, поддерживаемого IE10.
* `flexwrap` для свойства `flex-wrap`, которого нет в некоторых реализациях.

**Примечание:** вы можете найти список того, что означают все имена классов — см. Функции, обнаруженные Modernizr.

Далее, давайте обновим наш CSS, чтобы использовать Modernizr вместо `@supports`. Перейдите в `modernizr-css.css`, и замените два блока `@supports` следующим:

```css
/\* Properties for browsers with modern flexbox \*/

.flexbox main {
  display: flex;
}

.flexbox main div {
  padding-right: 4%;
  flex: 1;
}

.flexbox main div:last-child {
  padding-right: 0;
}

/\* Fallbacks for browsers that don't support modern flexbox \*/

.no-flexbox main div {
  width: 22%;
  float: left;
  padding-right: 4%;
}

.no-flexbox main div:last-child {
  padding-right: 0;
}

.no-flexbox footer {
  clear: left;
}
```

Так как же это работает? Поскольку все эти имена классов были помещены в элемент `<html>` вы можете настроить таргетинг на браузеры, которые поддерживают или не поддерживают функцию, используя определённые селекторы-потомки. Поэтому здесь мы применяем верхний набор правил только для браузеров, которые поддерживают flexbox, а нижний набор правил - только для браузеров, которые не поддерживают (`no-flexbox`).

**Примечание:** Имейте в виду, что все тесты функций HTML и JavaScript Modernizr также представлены в этих именах классов, так что вы можете свободно применять CSS выборочно в зависимости от того, поддерживает ли браузер функции HTML или JavaScript, если это необходимо.

**Примечание:** Если у вас возникли проблемы с выполнением этого, проверьте ваш код по файлам `modernizr-css.html` и `modernizr-css.css` (см. Также этот запуск в реальном времени).

### JavaScript

Modernizr также одинаково хорошо подготовлен для реализации функций обнаружения JavaScript. Это достигается за счёт того, что глобальный объект `Modernizr` становится доступным для страницы, к которой он применяется, и содержит результаты функции, определяемой как свойства `true`/`false`.

Например, загрузите наш пример `modernizr-css.html` в своём браузере, затем попробуйте перейти на консоль JavaScript и набрать `Modernizr.`, а после некоторые из этих имён классов (они тоже здесь одинаковы). Например:
```

Modernizr.flexbox
Modernizr.websqldatabase
Modernizr.xhr2
Modernizr.fetch
```

Консоль вернёт значения `true`/`false`, чтобы указать, поддерживает ли ваш браузер эти функции или нет.

Давайте посмотрим на пример, чтобы показать, как вы бы пользовали эти свойства.

1. Прежде всего, сделайте локальную копию файла примера `modernizr-js.html`.
2. Присоедините библиотеку Modernizr к HTML, используя элемент `<script>` , как мы делали в предыдущих демонстрациях. Поместите его над существующим элементом `<script>` который прикрепляет API Google Maps к странице.
3. Затем заполните текст-заполнитель `YOUR-API-KEY` во втором элементе `<script>` (как он есть сейчас) действительным ключом API Google Maps. Чтобы получить ключ, войдите в учётную запись Google, перейдите на страницу Получить ключ / Аутентификация затем нажмите синюю кнопку *Get a Key* и следуйте инструкциям.
4. Наконец, добавьте ещё один элемент `<script>` внизу тела HTML (непосредственно перед тегом `</body>` ) и поместите следующий скрипт в теги:

```js
if (Modernizr.geolocation) {
  navigator.geolocation.getCurrentPosition(function (position) {
    let latlng = new google.maps.LatLng(
      position.coords.latitude,
      position.coords.longitude,
    );
    let myOptions = {
      zoom: 8,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.TERRAIN,
      disableDefaultUI: true,
    };
    let map = new google.maps.Map(
      document.getElementById("map\_canvas"),
      myOptions,
    );
  });
} else {
  const para = document.createElement("p");
  para.textContent = "Argh, no geolocation!";
  document.body.appendChild(para);
}
```

Опробуйте свой пример! Здесь мы используем тест `Modernizr.geolocation`, чтобы проверить, поддерживается ли геолокация текущим браузером. Если это так, мы запускаем некоторый код, который получает текущее местоположение вашего устройства и отображает его на карте Google.

Подведение итогов
-----------------

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

Далее мы начнём изучать автоматизированное тестирование.

* Назад  (en-US)
* Обзор: Cross browser testing
* Далее  (en-US)