Следуйте этим простым шагам, чтобы создать полнофункциональный веб-сайт, используя Angular.
Как создать полностраничный веб-сайт в Angular. Часть 1 (4)
Как создать полностраничный веб-сайт в Angular. Часть 2 (4)
Как создать полностраничный веб-сайт в Angular. Часть 3 (4)
Как создать полностраничный веб-сайт в Angular. Часть 4 (4)
12. Добавление пользовательской директивы
А теперь, самая интересная часть! В целом наш сайт работает, за исключением того факта, что наше фоновое изображение не ресайзится, заполняя все пространство браузера. Мы собираемся решить эту проблему, создав кастомную директиву, которая будет ресайзить наше изображение на всю высоту и ширину страницы.
CLI снова пойдет нам на пользу, так как мы можем использовать его для создания директивы. Мы сгенерируем директиву fullpage
в каталоге app/shared/directives
.
1 2 |
mkdir src/app/shared/directives ng g directive shared/directives/fullpage |
Сгенерируется базовая директива, которая выглядит так:
1 2 3 4 5 6 7 8 9 |
ts import { Directive } from '@angular/core'; @Directive({ selector: '[appFullpage]' }) export class FullpageDirective { constructor() { } } |
Сгенерированный селектор — appFullpage
, кажется мне странным, поэтому я переименовал его в fullpage
. Вы можете переименовать его на свое усмотрение.
Основное различие между компонентом и директивой состоит в том, что директива не имеет своего собственного шаблона; она отвечает за украшение или расширение существующего элемента. В нашем случае мы хотим, чтобы она взяла существующий элемент и разместила на все окно браузера.
13. Доступ к элементу
Чтобы изменить размер элемента, нам нужна ссылка на него, которую нам предоставляет ElementRef
. Это даст нам доступ к элементу, объявленному в нашей директиве.
1 2 3 4 5 6 |
@Directive({ selector: '[fullpage]' }) export class FullpageDirective { constructor(private element: ElementRef) { } } |
Скучные математические выражения! Мы создадим функцию resize
, которая измеряет ширину и высоту нашего элемента, а также ширину и высоту окна, а затем пропорционально изменит размеры элемента. Основная идея заключается в том, чтобы сперва растянуть по меньшей ширине или высоте окна, а затем пропорционально масштабировать другое свойство.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
// app/shared/directives/fullpage.directive.ts ... export class FullpageDirective { constructor(private element: ElementRef) { } resize() { let bgwidth = this.element.nativeElement.width; let bgheight = this.element.nativeElement.height; let winwidth = window.innerWidth; let winheight = window.innerHeight; let widthratio = winwidth / bgwidth; let heightratio = winheight / bgheight; let widthdiff = heightratio * bgwidth; let heightdiff = widthratio * bgheight; if (heightdiff > winheight) { this.element.nativeElement.width = winwidth; this.element.nativeElement.height = heightdiff; } else { this.element.nativeElement.width = widthdiff; this.element.nativeElement.height = winheight; } } } |
14. Введение слушателей
Все это прекрасно, но как мы узнаем, когда изменять размер элемента? Мы хотим изменить размер нашего элемента, когда он только загрузился, и каждый раз при изменении размера окна.
Следующий вопрос: откуда мы знаем, когда происходят эти события? Angular предлагает отличный способ сделать это в виде HostListener
. Добавляем метод с метаданными HostListener
, где определяем событие, которое мы хотим прослушать, чтобы запустить код при возникновении этого события.
Мы используем window:resize
, чтобы узнать, когда окно было изменено и load
, когда окно загрузилось.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// app/shared/directives/fullpage.directive.ts import { Directive, ElementRef, HostListener } from '@angular/core'; ... export class FullpageDirective { constructor(private element: ElementRef) { } @HostListener('window:resize', ['$event']) onResize(event) { this.resize(); } @HostListener('load', ['$event']) onLoad(event) { this.resize(); } resize() { ... } } |
Это действительно потрясающий способ прикреплять методы к событиям DOM без прямого общения с DOM или написания наших слушателей вручную и, самое главное, не беспокоиться об уничтожении наших событий.
Чтобы добавить директиву в наше приложение, перейдем к файлу page.component.html
и добавим атрибут fullpage
к нашему изображению.
1 2 3 |
<!-- app/page/page.component.html --> <img class="fullBg" fullpage [src]="page.image"> ... |
15. Оформляем элементы с помощью CSS
Оформим некоторые элементы с помощью CSS, чтобы они смотрелись красиво. Укажем что мы используем Flexbox для нашего макета и хотим, чтобы наш тег body
скрывал любое переполнение (overflow).
1 2 3 4 5 6 7 8 9 10 11 |
/* styles.css */ html, body, app-root { width: 100%; height: 100%; display: flex; flex-direction: column; } body { overflow: hidden; margin:0; } |
Также обратите внимание, что мы создаем класс spacer,
чтобы отправить логотип и кнопки на панель инструментов. У нас также есть классactive
, который мы используем с routerLinkActive
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/* app/app.component.css */ md-toolbar { position: relative; z-index: 1; overflow-x: auto; } md-toolbar-row { justify-content:space-between; } .spacer { flex: 1 1 auto; } a.active { background-color: rgba(0,0,0, 0.3); } h1 { margin: 0; } h1 .light { font-weight: 100; } |
Наконец, мы используем псевдо-селектор :host
для таргетинга компонента, на который нацелен наш CSS.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/* app/page/page.component.css */ :host { display: flex; height: 100%; align-items: center; } md-card { width:500px; background: rgba(255,255,255,0.9); } md-card-header { color: #3f51b5; } md-card-content { padding: 8px; } .fullBg { z-index:0; position: fixed; top: 0; left: 0; } |
Интересная вещь с CSS заключается в том, что он определен на соответствующем уровне компонента. Стили в рамках приложения обычно входят в файл styles.css
, каждый из которых соответствует конкретному стилю в соответствующих файлах CSS.
16. Смотрим свою работу
В первой части этой серии мы рассмотрели немало вопросов, но давайте рассмотрим, что мы сделали:
- Мы использовали
@angular/cli
для генерации нового проекта - Мы установили
@angular/material
и@angular/animations
через NPM - Мы добавили
@angular/material
и@angular/animations
в наш Angular модуль - Мы создали
PageComponent
для представления страниц на нашем сайте - Мы создали
ContentService
для хранения контента нашего сайта - Мы создали маршруты, которые сопоставлялись со страницами на нашем сайте и передавались в кастомном
data
, чтобы помочь нам определить, на какой странице мы находимся - Мы добавили тулбар, связанный с каждой страницей с помощью
routerLink
, и создали кнопку для активной страницы сrouterLinkActive
- Мы создали директиву
fullpage
, чтобы изменить размер изображения в нашемPageComponent
, и заполнить весь фон - Мы использовали
HostListener
для прослушивания событий DOM, чтобы знать, когда меняется размер элемента
Источник creativebloq.com