Если вы когда-либо создавали приложения с Angular 2, то знаете, что первоначальная настройка проекта отнимает немало времени. К счастью, команда Angular создала Angular CLI — утилиту командной строки, облегчающую эту задачу.
В этой статье мы построим клиента Hacker News, используя Angular CLI, RxJS Observables и Webpack как загрузчик модулей.
Готовое приложение.
Исходный код.
Мы постепенно, шаг за шагом, пройдём весь процесс построения приложения и я постараюсь подробно объяснять важные моменты по ходу дела, а также сделанные мной ошибки и способы их решения.
Вот краткий список того, что нам предстоит сделать:
- Мы начнём с построения каркаса приложения, главной страницы Hacker News
- Затем подключим Observable Data Service для асинхронной загрузки данных
- Добавим роутинг с Angular Component Router для построения навигации между страницами и видами топиков
- И, наконец, добавим роуты чтобы пользователь мог перейти к комментариям к топику и в профили пользователей.
Приступим
Убедитесь, что у вас установлен Node и npm, затем установите CLI в терминале:
npm install -g @angular/cli
Создадим и запустим приложение:
ng new angular2-hn
cd angular2-hn
ng serve
Откройте браузер по адресу https://localhost:4200/
Круто, да?
Настроим Sass как препроцессор CSS:
ng set defaults.styleExt scss
Создадим первый компонент HeaderComponent
ng generate component Header
Будет создана папка header, содержащая такие файлы:
- header.component.scss
- header.component.html
- header.component.ts
- header.component.spec.ts
Посмотрим на файл app.module.ts и увидим, что наш компонент уже задекларирован:
// app.module.ts
// ...
import { AppComponent } from './app.component';
import { HeaderComponent } from './header/header.component';
@NgModule({
declarations: [
AppComponent,
HeaderComponent
],
//...
А взглянув в файл header.component.ts, вы увидите, что селектор компонентов — app-header. Добавим его в наш корневой компонент, app.component.ts.
Запустим приложение. Компонент header загрузился нормально:
Супер. Теперь добавим кое-какую разметку и стили.
Стили из файла app.component.scss можете скачать здесь. Перейдём к header.
Стили этого компонента можно скачать здесь. Запустим приложение:
Наше приложение должно быть отзывчивым. Посмотрим, как оно выглядит сейчас на уменьшенном экране:
Но у нас с края появился непредвиденный отступ. Это из-за того, что элемент body имеет отступ по-умолчанию (через margin):
Но если открыть app.component.scss, там указано правило margin: 0 для экранов меньше 768px:
$mobile-only: "only screen and (max-width : 768px)";
body {
margin-bottom: 0;
@media #{$mobile-only} {
margin: 0;
}
}
Так почему же оно так работает? Это из-за способа, которым Angular инкапсулирует CSS-стили компонента. Не будем вдаваться в детали, но есть три способа, которые может использовать Angular для этого:
- None: Angular ничего не предпринимает — ни инкапсуляции, ни Shadow DOM, просто обычная загрузка стилей.
- Emulated: Angular эмулирует поведение Shadow DOM. Это способ по-умолчанию.
- Native: Angular использует нативный Shadow DOM браузера (только в браузерах, имеющих соответствующую поддержку).
В корневом компоненте мы добавляем стили элементу body, но оно не работает, потому что мы не указали Angular не применять никаких действий к представлению компонента:
// app.component.ts
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'app-root',
encapsulation: ViewEncapsulation.None,
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
}
Перезапустим приложение и посмотрим на него. Теперь стили применились как и должно.
Несколько компонентов
Добавим ещё пару компонентов, Stories и Footer. Stories представляют топики в Hacker News, и мы начнём с каркаса, добавив в него упорядоченный список.
ng g component Stories
// stories.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-stories',
templateUrl: './stories.component.html',
styleUrls: ['./stories.component.scss']
})
export class StoriesComponent implements OnInit {
items: number[];
constructor() {
this.items = Array(30);
}
ngOnInit() {
}
}
- Story #{{i}}
Стили для Stories можно взять здесь. Подвал страницы очень простой (стили для него скачайте тут).
ng g component Footer
Обновим корневой компонент, чтобы увидеть добавленные компоненты:
Вот так теперь выглядит приложение:
Так как каждый топик, или элемент, будет иметь собственные атрибуты, имеет смысл создать отдельный компонент для этого.
ng g component Item
Когда у нас будут реальные данные, нужно будет передавать идентификатор элемента из компонента топиков его дочернему элементу. Тем временем, сделаем передачу позиции списка как itemID:
// item.component.ts
import { Component, Input, OnInit } from '@angular/core';
@Component({
selector: 'item',
templateUrl: './item.component.html',
styleUrls: ['./item.component.scss']
})
export class ItemComponent implements OnInit {
@Input() itemID: number;
constructor() { }
ngOnInit() {
}
}
Story #{{itemID}}
Перезапустите приложение, всё должно работать так же, а это значит, что параметр позиции передаётся успешно с @Input.
Итак, у нас получился отличный каркас главной страницы. Здесь исходный код примера на текущем этапе.
Разработчик: java, kotlin, c#, javascript, dart, 1C, python, php.
Пишите: @ighar. Buy me a coffee, please :).