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

Во второй части мы рассмотрели создание децентрализованного приложения Angular — необходимые условия и создание каркасного приложения Angular.

В этой части, части III, мы рассмотрим стилизацию Angular, включая пользовательские компоненты.

Стилизация приложения Angular

Наше приложение из предыдущей статьи еще не оформлено и показывает только текст с заголовком, страницей и нижним колонтитулом; однако, прежде чем мы начнем стилизовать, полезно
понять архитектуру стилей Angular, чтобы убедиться, что мы не получим
файл каскадных таблиц стилей (CSS), который слишком велик для управления.

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

Кроме того, было бы неплохо быстро перейти от нуля к стилизованному приложению.
Это можно сделать с помощью Angular Material. Angular Material дает вам возможность
получить единообразный «вид» вашего приложения без всех хлопот,
размышлений о программировании для разных браузеров и устройств. Давайте взглянем.

Угловая архитектура

Angular настроен на глобальный файл CSS. Этот файл CSS называется style.css, и вы можете найти его в корне проекта.

src/style.css 

Файл содержит стили, которые вы хотите использовать для всего приложения, например шрифты, темы, стили для всех компонентов и т. д.

Как вы видели, каждый компонент также включает частный файл CSS. В CSS-файл
конкретного компонента помещаются уникальные стили, которые
используются только для этого компонента.

Например,

/src/app/components/footer/footer.component.css

содержит стили, характерные для компонента нижнего колонтитула.

Угловой материал

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

Другой потенциальной проблемой является тестирование. Все различные браузеры, версии
браузеров, размеры экрана и устройства должны быть протестированы, а создание ваших
страниц с нуля потребует строгого тестирования и группы обеспечения качества (QA)
, чтобы гарантировать он работает согласованно на разных устройствах.

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

Для получения дополнительной информации посетите страницу начала работы с Angular Material:
https://material.angular.io/guide/getting-started.

Установить угловой материал

Есть несколько способов установить Material. Поскольку вы установили
Angular DevKit, вы можете просто запустить команду ng add, чтобы получить
библиотеку Angular Material. Вам нужно сначала установить cdk, потому что это
зависимость.

ng add @angular/cdk

Далее устанавливаем материал.

ng add @angular/material

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

Мастер установки позволяет вам выбрать, что вы хотите установить, я использовал следующие настройки; (вы можете узнать больше об этих функциях в документах Angular Material).

? Choose a prebuilt theme name, or "custom" for a custom theme: Indigo/Pink [Preview: https://material.angular.io?theme=indigo-pink]
? Set up HammerJS for gesture recognition? Yes
? Set up browser animations for Angular Material? Yes 

Ожидаемый результат должен показывать файлы, которые были обновлены:

UPDATE package.json (1434 bytes)
✔ Packages installed successfully.
UPDATE src/main.ts (391 bytes)
UPDATE src/app/app.module.ts (878 bytes)
UPDATE angular.json (3740 bytes)
UPDATE src/index.html (487 bytes)
UPDATE src/styles.css (181 bytes)

Затем вы хотите изменить свое приложение, чтобы Angular Material включал анимацию, значки материалов, поддержку жестов и модули компонентов.

В своем проекте вы будете использовать только модули компонентов, а не
все функции, которые может предложить Angular Material; вам нужно
импортировать NgModule для каждого компонента, который вы хотите использовать. Открытым;

src/app/app.module.ts 

Добавьте операторы импорта;

import {
  MatButtonModule,
  MatCheckboxModule,
  MatInputModule,
  MatSelectModule,
  MatDatepickerModule,
  MatNativeDateModule
} from '@angular/material';

Затем обновите операторы импорта @NgModule, чтобы включить импортированные вами
модули материалов.

imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
MatButtonModule,
MatInputModule,
MatDatepickerModule,
MatNativeDateModule,
MatCheckboxModule,
MatSelectModule
]

Вот и все. Теперь у вас есть доступ к компонентам Angular Material
, которые вы включили.

Тема для вашего приложения Angular Material

Теперь, когда у вас есть доступ к компонентам Angular Material, вы можете
использовать темы для их оформления. Тема — это набор цветов, которые будут использоваться
в ваших компонентах Angular Material.

В Angular Material тема создается путем создания нескольких палитр.

Основная палитра: это цвета, которые чаще всего используются
на всех экранах и компонентах.

Палитра акцентов: цвета, используемые для кнопки
и интерактивных элементов.

Палитра предупреждений: это цвета для ошибок.

Палитра переднего плана: это цвета для текста и значков.

Палитра фона: это цвета фона элемента.

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

Angular Material поставляется с несколькими готовыми файлами CSS
темы. Как вы, наверное, помните, у вас была возможность выбрать тему для использования
при установке Material.

Эти файлы темы также включают все стили для ядра (стили
общие для всех компонентов), поэтому вам нужно включить в свое приложение только один файл CSS
для Angular Material. Вы можете включить файл темы непосредственно
в ваше приложение из @angular/material/prebuilt-themes.
Доступны следующие готовые темы:

 — deeppurple-amber.css
 — indigo-pink.css
 — pink-bluegrey.css
 — purple-green.css

Здесь вы используете Angular CLI, поэтому можете просто включить стиль, который
хотите, в глобальный

src/styles.css 

Оригинальный контент;

/* You can add global styles to this file, and also import other style files */

html, body { height: 100%; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }

Добавьте следующий оператор импорта вверху документа:

@import “~@angular/material/prebuilt-themes/indigo-pink.css”;

Пока у вас открыт файл src/app.component.css, вы также можете создать стиль для контейнера, абзаца и кнопки, которые вы можете использовать в своем приложении для своих страниц.

p {
  padding-left: 20px;
  font-size: 12px;
}
.container {
  margin-right: auto;
  margin-left: auto;
  padding: 20px 15px 30px;
  width: 750px;
}
button {
  color: #ffffff;
  background-color: #611BBD;
  border-color: #130269;
  display: inline-block;
  margin-bottom: 0;
  font-weight: normal;
  text-align: center;
  vertical-align: middle;
  touch-action: manipulation;
  cursor: pointer;
  white-space: nowrap;
  padding: 6px 12px;
  font-size: 12px;
  line-height: 1.42857143;
  border-radius: 4px;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

Создание контента

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

Компонент нижнего колонтитула

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

src/app/components/footer/footer.component.html 

И замените код по умолчанию.

<p>
footer works!
</p>

Замените код, создав контейнер div со стилем, который вы добавили
в глобальный файл CSS.

<div class="ng-scope">
  <div class="container">
    <p>Copyright © 2019 Company Name. All Rights Reserved.</p>
  </div>
</div>

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

src/app/components/footer/footer.component.css

И вставьте следующее:

p {
  padding-left: 0;
  font-size: 11px;
}

Обратите внимание, что вы определили тег ‹p› дважды, один раз в глобальном файле CSS
и один раз на уровне компонента. Что произойдет, так это то, что глобальный тег
‹p› будет перезаписан компонентом ‹p›, поэтому вы можете использовать тег ‹p›
для нижнего колонтитула и другой тег ‹p› для другие компоненты, такие как
начальная страница и страница перехода, сохраняя при этом код HTML свободным от кода CSS.

Компонент заголовка

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

src/app/components/header/header.component.css 

и добавьте стили навигационного списка.

.nav {
  margin-bottom: 0;
  padding-left: 0;
  list-style: none;
}
li {
  display: block;
  float: left;
  width: 100px;
  height: 25px;
  padding: 5px;
}
.nav>li>a {
  margin-bottom: 0;
  padding-left: 0;
  font-weight: 500;
  font-size: 12px;
  text-transform: uppercase;
  position: relative;
}

За;

src/app/components/header/header.component.html

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

<p>
header works!
</p>

со следующим;

<div class="ng-scope">
  <div class="container">
    <ul class="nav">
      <li>
        <a routerLink='/start'>home</a>
      </li>
      <li>
        <a routerLink='/transfer'>transfer</a>
      </li>
    </ul>
  </div>
</div>

Рабочее децентрализованное приложение теперь включает базовые стили и функциональную навигацию,
как показано на рис. 1.

Как вы помните, запустите ng serve, если он еще не запущен;

ng serve

Компонент передачи

Компонент перевода будет содержать форму, которую вы отправите для перевода
монет Ethereum с одного адреса учетной записи на другой. Вы будете использовать
модуль форм, чтобы ускорить создание формы. Для этого вам нужно
включить модули форм FormsModule и ReactiveFormsModule
в app.module.ts точно так же, как вы делали это с другими модулями материалов.
Open;

src/app/app.module.ts 

И добавьте следующий оператор импорта:

import { FormsModule, ReactiveFormsModule } from ‘@angular/forms’;

Вы также хотите обновить оператор импорта.

imports: [
  FormsModule,
  ReactiveFormsModule,
  ...
  ...
],

Вы будете использовать тег ‹mat-form-field›, представляющий компонент, объединяющий несколько компонентов Angular Material вместе и применяющий общие стили текстовых полей, такие как подчеркивание, плавающая метка и сообщения-подсказки. Это ускорит разработку, так как вам не нужно будет реализовывать все это и тестировать их на нескольких устройствах/браузерах. Поле формы — это компонент-оболочка с именем ‹mat-form-field›.

Вы можете использовать любые элементы управления полем формы (такие как ввод, текстовое поле, список и т. д.).
Вы можете найти информацию о мат-формах здесь: https://material.
angular.io /components/form-field/обзор
.

За;

src/app/components/transfer/transfer.component.ts

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

import {FormBuilder, FormControl, FormGroup, Validators} from ‘@angular/forms’;

Затем вам нужно обновить определение компонента, чтобы реализовать метод OnInit.

export class TransferComponent implements OnInit {

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

formSubmitted = false;
userForm: FormGroup;
user: any;

Чтобы проверить вашу форму, вы определите сообщения в случае, если форма
не заполнена неправильно. Каждый элемент управления "форма" должен быть определен с обязательными
полями и сообщениями.

accountValidationMessages = {
  transferAddress: [
    { type: 'required', message: 'Transfer Address is required' },
    { type: 'minLength', message: 'Transfer Address must be 42 characters long' },
    { type: 'maxLength', message: 'Transfer Address must be 42 characters long' }
  ],
  amount: [
    { type: 'required', message: 'Amount is required' },
    { type: 'pattern', message: 'Amount must be a positive number' }
  ],
  remarks: [
    { type: 'required', message: 'Remarks are required' }
  ]
};

При создании конструктора необходимо включить компонент FormBuilder
, чтобы иметь возможность генерировать форму.

constructor(private fb: FormBuilder) { }

Когда ваш компонент получает инициализацию, вы устанавливаете флаг «formSubmitted»
в false и устанавливаете значения по умолчанию для информации пользователя. Затем вы
вызовете метод для получения учетной записи пользователя и баланса, который
реализуете позже. Наконец, вы вызовете метод createForms, который
создаст форму.

ngOnInit() {
  this.formSubmitted = false;
  this.user = {address: '', transferAddress: '', balance: '', amount: '', remarks: ''};
  this.getAccountAndBalance();
  this.createForms();
}

Метод createForms создаст элементы управления формы, минуя
валидаторы и данные.

createForms() {
  this.userForm = this.fb.group({
    transferAddress: new FormControl(this.user.transferAddress, Validators.compose([
      Validators.required,
      Validators.minLength(42),
      Validators.maxLength(42)
    ])),
    amount: new FormControl(this.user.amount, Validators.compose([
      Validators.required,
      Validators.pattern('^[+]?([.]\\d+|\\d+[.]?\\d*)$')
    ])),
    remarks: new FormControl(this.user.remarks, Validators.compose([
      Validators.required
    ]))
  });
}

Метод getAccountAndBalance установит адрес учетной записи пользователя
и баланс; сейчас вы используете фиктивные данные, но позднее в этой статье вы реализуете
реальную службу.

getAccountAndBalance = () => {
  const that = this;
  that.user.address = '0xd8d0101f83e79fb4e8d21134f5325e64816bd6a0';
  that.user.balance = 0;
  // TODO: fetch data
}

Наконец, после отправки формы вам нужен метод для обработки данных
и вызова службы. submitForm будет использоваться для проверки правильности
формы, а затем позже вы вызовете сервисный компонент, который
создадите.

submitForm() {
  if (this.userForm.invalid) {
    alert('transfer.components :: submitForm :: Form invalid');
    return;
  } else {
    console.log('transfer.components :: submitForm :: this.
    userForm.value');
    console.log(this.userForm.value);
    // TODO: service call
  }
}

Вот полный код для transfer.component.ts;

import { Component, OnInit } from '@angular/core';
import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms';

@Component({
  selector: 'app-transfer',
  templateUrl: './transfer.component.html',
  styleUrls: ['./transfer.component.css']
})
export class TransferComponent implements OnInit {

  formSubmitted = false;
  userForm: FormGroup;
  user: any;

  accountValidationMessages = {
    transferAddress: [
      { type: 'required', message: 'Transfer Address is required' },
      { type: 'minLength', message: 'Transfer Address must be 42 characters long' },
      { type: 'maxLength', message: 'Transfer Address must be 42 characters long' }
    ],
    amount: [
      { type: 'required', message: 'Amount is required' },
      { type: 'pattern', message: 'Amount must be a positive number' }
    ],
    remarks: [
      { type: 'required', message: 'Remarks are required' }
    ]
  };

  constructor(private fb: FormBuilder) { }

  ngOnInit() {
    this.formSubmitted = false;
    this.user = {address: '', transferAddress: '', balance: '', amount: '', remarks: ''};
    this.getAccountAndBalance();
    this.createForms();
  }

  createForms() {
    this.userForm = this.fb.group({
      transferAddress: new FormControl(this.user.transferAddress, Validators.compose([
        Validators.required,
        Validators.minLength(42),
        Validators.maxLength(42)
      ])),
      amount: new FormControl(this.user.amount, Validators.compose([
        Validators.required,
        Validators.pattern('^[+]?([.]\\d+|\\d+[.]?\\d*)$')
      ])),
      remarks: new FormControl(this.user.remarks, Validators.compose([
        Validators.required
      ]))
    });
  }
  getAccountAndBalance = () => {
    const that = this;
    that.user.address = '0xd8d0101f83e79fb4e8d21134f5325e64816bd6a0';
    that.user.balance = 0;
    // TODO: fetch data
  }
  submitForm() {
    if (this.userForm.invalid) {
      alert('transfer.components :: submitForm :: Form invalid');
      return;
    } else {
      console.log('transfer.components :: submitForm :: this.userForm.value');
      console.log(this.userForm.value);
      // TODO: service call
    }
  }
}

За;

transfer.component.html

Мы установим тег формы для вызова метода submitForm после отправки формы.

<form [formGroup]="userForm" (ngSubmit)="submitForm()"
      novalidate autocomplete="off">
  <div class="container">
    <div class="transfer-container">
      <div>
        Address: {{user.address}} <br/>
        Balance: {{user.balance}} Eth
      </div>

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

Для управления формой вам нужны поля ввода для счета, на который вы
переводите средства, суммы и сообщения. Вам также необходимо настроить
проверки.

<mat-form-field>
  <input matInput placeholder="Transfer Address" name="transferAddress" formControlName="transferAddress"
         maxlength="42" minlength="42" required>
  <mat-error *ngFor="let validation of accountValidationMessages.transferAddress">
    <mat-error *ngIf="userForm.get('transferAddress').hasError(validation.type) && (userForm.get('transferAddress').dirty || userForm.get('transferAddress').touched)">{{validation.message}}</mat-error>
  </mat-error>
</mat-form-field>
<mat-form-field>
  <input matInput placeholder="Amount" name="amount" formControlName="amount" required>
  <mat-error *ngFor="let validation of accountValidationMessages.amount">
    <mat-error *ngIf="userForm.get('amount').hasError(validation.type) && (userForm.get('amount').dirty || userForm.get('amount').touched)">{{validation.message}}</mat-error>
  </mat-error>
</mat-form-field>
<mat-form-field>
  <input matInput placeholder="Remarks" name="remarks" formControlName="remarks"
         maxlength="42" required>
  <mat-error *ngFor="let validation of accountValidationMessages.remarks">
    <mat-error *ngIf="userForm.get('remarks').hasError(validation.type) && (userForm.get('remarks').dirty || userForm.get('remarks').touched)">{{validation.message}}</mat-error>
  </mat-error>
</mat-form-field>

Наконец, не забудьте закрыть элементы div и форму, а также добавить кнопку
отправки.

<div style="width: 100px">
        <button type="submit">Transfer Ether</button>
      </div>
    </div>
  </div>
</form>

Для transfer.component.css мы будем использовать переходный контейнер
для форматирования вашей формы по горизонтали.

.transfer-container {
  display: flex;
  flex-direction: column;
}
.transfer-container > * {
  width: 100%;
}

Вот и все. Теперь вы можете проверить свое децентрализованное приложение в браузере, и вы должны
иметь возможность видеть данные пользователя по умолчанию, тестировать форму, проверять ее и отправлять
форму. См. рис. 2.

Вот полный файл transfer.component.html;

<form [formGroup]="userForm" (ngSubmit)="submitForm()"
      novalidate autocomplete="off">
  <div class="container">
    <div class="transfer-container">
      <div>
        Address: {{user.address}} <br/>
        Balance: {{user.balance}} Eth
      </div>
      <mat-form-field>
        <input matInput placeholder="Transfer Address" name="transferAddress" formControlName="transferAddress"
               maxlength="42" minlength="42" required>
        <mat-error *ngFor="let validation of accountValidationMessages.transferAddress">
          <mat-error *ngIf="userForm.get('transferAddress').hasError(validation.type) && (userForm.get('transferAddress').dirty || userForm.get('transferAddress').touched)">{{validation.message}}</mat-error>
        </mat-error>
      </mat-form-field>
      <mat-form-field>
        <input matInput placeholder="Amount" name="amount" formControlName="amount" required>
        <mat-error *ngFor="let validation of accountValidationMessages.amount">
          <mat-error *ngIf="userForm.get('amount').hasError(validation.type) && (userForm.get('amount').dirty || userForm.get('amount').touched)">{{validation.message}}</mat-error>
        </mat-error>
      </mat-form-field>
      <mat-form-field>
        <input matInput placeholder="Remarks" name="remarks" formControlName="remarks"
               maxlength="42" required>
        <mat-error *ngFor="let validation of accountValidationMessages.remarks">
          <mat-error *ngIf="userForm.get('remarks').hasError(validation.type) && (userForm.get('remarks').dirty || userForm.get('remarks').touched)">{{validation.message}}</mat-error>
        </mat-error>
      </mat-form-field>
      <div style="width: 100px">
        <button type="submit">Transfer Ether</button>
      </div>
    </div>
  </div>
</form>

Угловые директивы

Создание директив в Angular дает вам возможность создавать собственные
пользовательские HTML-теги с помощью всего нескольких строк кода, как вы видели в форме
Material. Вы можете включать пользовательские теги, объединяющие многие
компоненты. На высоком уровне директивы — это маркеры элемента DOM.
Эти маркеры могут указывать на любой компонент DOM, от атрибута
до имени элемента или даже комментария или класса CSS. Затем эти маркеры
сообщают компилятору HTML AngularJS, что нужно прикрепить указанное поведение или
преобразовать весь элемент DOM и его дочерние элементы на основе определенной логики.

Angular поставляется со многими из этих встроенных директив. Однако во время
разработки вы, скорее всего, будете создавать свои собственные директивы.
Теперь ваше децентрализованное приложение простое, поэтому вам не нужно создавать никаких директив, и
это выходит за рамки объем этой статьи, чтобы объяснить это. Если вам нужно сгенерировать директиву каркаса, используйте Angular CLI точно так же, как вы создавали
другие компоненты.

ng generate directive {directive-name}

Хотя вы не создаете директиву в своем приложении, я хотел
познакомить вас с концепцией, поскольку она является неотъемлемой частью создания проекта Angular
.

Давайте подведем итоги!

До сих пор мы глубоко погрузились в то, что такое децентрализованные приложения, и рассмотрели классификации и проекты децентрализованных приложений
. Мы узнали, как начать свой собственный проект децентрализованного приложения
, разбив процесс на пять этапов: написание технического документа, запуск ICO, разработка децентрализованного приложения, его запуск и продвижение вашего децентрализованного приложения.

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

Далее вы узнали, как импортировать проект Angular в WebStorm или создать новый проект. Вы рассмотрели части, из которых состоит Angular, такие как компоненты, модули и директивы. Вы также узнали, как стилизовать децентрализованное приложение, поняв архитектуру в стиле Angular и работая с Angular Material.

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

В следующих статьях вы создадите смарт-контракт передачи и проект разработки Truffle, а также подключитесь к сети разработки Ganache.

Вы узнаете, как работать с сетью Ethereum через Truffle
и протестируете свой смарт-контракт. Вы также свяжете свое децентрализованное приложение с библиотекой web3 сети Ethereum
и подключитесь через MetaMask.

Куда пойти отсюда

Продолжайте следить за нашими статьями, так как в следующих статьях мы расскажем о следующем;

Чтобы узнать больше о том, что возможно с Blockchain, а также о разработке собственного проекта, проверьте Разработчик Blockchain.