
Previously, we looked at creating and setting up a new Angular project. In this article we will analyze the basic structure.
Let me remind you that the series is devoted to the development of a web application for searching for airline tickets and hotels. The project is based on a project from Alfa Travel - travel.alfabank.ru
The site consists of the following blocks:
This allows us to highlight the main parts:
Change the AppComponent so that it only outputs routerOutlet.
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'baf-root',
standalone: true,
imports: [RouterOutlet],
template: '<router-outlet/>',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {}
Delete unused files: app.component.spec.ts, app.component.scss and app.component.html.
Add configuration for the browser version in app.config.browser.ts:
import { ApplicationConfig, mergeApplicationConfig } from '@angular/core';
import { provideAnimations } from '@angular/platform-browser/animations';
import { appConfig } from './app.config';
const browserConfig: ApplicationConfig = {
providers: [provideAnimations()],
};
export const config = mergeApplicationConfig(appConfig, browserConfig);
And import it into main.ts:
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { config } from './app/app.config.browser';
bootstrapApplication(AppComponent, config).catch((err) => console.error(err));
For the mobile version we need to work with touches and swipes, so we use hammerjs
Install the dependency:
yarn add -D hammerjs @types/hammerjs
Connect animation and hammerjs in the browser:
import 'hammerjs';
import { ApplicationConfig, mergeApplicationConfig } from '@angular/core';
import { provideAnimations } from '@angular/platform-browser/animations';
import { appConfig } from './app.config';
const browserConfig: ApplicationConfig = {
providers: [provideAnimations()],
};
export const config = mergeApplicationConfig(appConfig, browserConfig);
You need to set the configuration for hammerjs.
Create a new core folder, in which we will store everything that is an integral part of the project.
mkdir src/app/core mkdir src/app/core/lib echo >src/app/core/index.ts mkdir src/app/core/lib/hammer echo >src/app/core/lib/hammer/hammer.ts
In hammer.ts we specify the config:
import { EnvironmentProviders, importProvidersFrom, Injectable, Provider } from '@angular/core';
import { HAMMER_GESTURE_CONFIG, HammerGestureConfig, HammerModule } from '@angular/platform-browser';
@Injectable()
export class HammerConfig extends HammerGestureConfig {
override overrides = {
swipe: { velocity: 0.4, threshold: 20 },
pinch: { enable: false },
rotate: { enable: false },
};
}
export function provideHammer(): (Provider | EnvironmentProviders)[] {
return [
importProvidersFrom(HammerModule),
{
provide: HAMMER_GESTURE_CONFIG,
useClass: HammerConfig,
},
];
}
Export to src/app/core/index.ts:
export * from './lib/hammer/hammer';
For quick access, add an alias to tsconfig.json:
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"esModuleInterop": true,
"sourceMap": true,
"declaration": false,
"experimentalDecorators": true,
"moduleResolution": "bundler",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022",
"useDefineForClassFields": false,
"lib": ["ES2022", "dom"],
"baseUrl": ".",
"paths": {
"@baf/core": ["src/app/core/index.ts"]
}
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
Note that you also need to specify the baseUrl.
Connect in the browser version:
import { ApplicationConfig, mergeApplicationConfig } from '@angular/core';
import { provideAnimations } from '@angular/platform-browser/animations';
import { provideHammer } from '@baf/core';
import { appConfig } from './app.config';
const browserConfig: ApplicationConfig = {
providers: [provideAnimations(), provideHammer()],
};
export const config = mergeApplicationConfig(appConfig, browserConfig);
The layout is common to the entire web application. Let's add a new UI folder in which we will store the components.
mkdir src/app/ui mkdir src/app/ui/layout/lib echo >src/app/ui/layout/index.ts
Run the command:
yarn ng g c layout
Move the content to src/app/ui/layout/lib.
We see that everything is created without the attributes we need and with test files:
import { Component } from '@angular/core';
@Component({
selector: 'baf-layout',
standalone: true,
imports: [],
templateUrl: './layout.component.html',
styleUrl: './layout.component.scss'
})
export class LayoutComponent {}
In angular.json we will specify the properties:
{
"@schematics/angular:component": {
"style": "scss",
"changeDetection": "OnPush",
"skipTests": true
}
}
Edit LayoutComponent:
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'baf-results',
standalone: true,
imports: [RouterOutlet],
templateUrl: './layout.component.html',
styleUrl: './layout.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class LayoutComponent {}
Add a header, content and footer:
<router-outlet name="top" /> <header> <router-outlet name="header" /> </header> <main> <router-outlet name="main-top" /> <router-outlet /> <router-outlet name="main-bottom" /> </main> <footer> <router-outlet name="footer" /> </footer> <router-outlet name="bottom" />
A few styles:
:host {
display: flex;
min-height: 100vh;
flex-direction: column;
}
header,
footer {
flex-shrink: 0;
}
main {
flex-grow: 1;
overflow-x: hidden;
}
Export the component to src/app/ui/layout/index.ts:
export * from './lib/layout.component';
And write the alias in tsconfig.json:
{
"paths": {
"@baf/core": ["src/app/core/index.ts"],
"@baf/ui/layout": ["src/app/ui/layout/index.ts"]
}
}
Before displaying the layout, you need to configure the styles in the application.
To reset the default appearance in the browser, just the following:
/* You can add global styles to this file, and also import other style files */
@use '@angular/cdk' as cdk;
// Hack for global CDK dialogs styles
@include cdk.overlay();
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
-moz-text-size-adjust: none;
-webkit-text-size-adjust: none;
text-size-adjust: none;
}
blockquote {
margin: 0;
padding: 1rem;
}
h1 {
margin-block-start: 1.45rem;
margin-block-end: 1.45rem;
}
h2 {
margin-block-start: 1.25rem;
margin-block-end: 1.25rem;
}
h3 {
margin-block-start: 1.175rem;
margin-block-end: 1.175rem;
}
h4 {
margin-block-start: 1.15rem;
margin-block-end: 1.15rem;
}
figure {
margin: 0;
}
p {
margin-block-start: 1rem;
margin-block-end: 1rem;
}
ul[role='list'],
ol[role='list'] {
list-style: none;
}
body {
margin: 0;
min-height: 100vh;
line-height: 1.5;
font-family:
Arial,
ui-sans-serif,
system-ui,
-apple-system,
BlinkMacSystemFont,
sans-serif;
font-size: 16px;
}
h1,
h2,
h3,
h4,
button,
input,
label {
line-height: 1.1;
}
h1,
h2,
h3,
h4 {
text-wrap: balance;
}
a:not([class]) {
text-decoration-skip-ink: auto;
color: currentColor;
}
img,
picture {
max-width: 100%;
display: block;
}
input,
button,
textarea,
select {
font: inherit;
}
textarea:not([rows]) {
min-height: 10rem;
}
:target {
scroll-margin-block: 5ex;
}
Reset will be placed in styles.scss.
Edit index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>BuyAndFly</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet" />
<meta name="description" content="Example Angular 18 application for search for cheap flights and hotels." />
<link rel="preconnect" href="https://photo.hotellook.com" />
<link rel="apple-touch-icon" sizes="180x180" href="/favicons/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicons/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicons/favicon-16x16.png" />
<link rel="manifest" href="/site.webmanifest" />
<link rel="mask-icon" href="/favicons/safari-pinned-tab.svg" color="#172659" />
<meta name="msapplication-config" content="/browserconfig.xml" />
<meta name="msapplication-TileColor" content="#172659" />
<meta name="theme-color" content="#ffffff" />
</head>
<body>
<baf-root></baf-root>
</body>
</html>
Add the generated favicons to public, as well as other files:
browserconfig.xml:
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/favicons/mstile-150x150.png"/>
<TileColor>#172659</TileColor>
</tile>
</msapplication>
</browserconfig>
site.webmanifest:
{
"name": "Buy & Fly",
"short_name": "Buy & Fly",
"icons": [
{
"src": "/favicons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/favicons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone",
"start_url": ".",
"description": "Search for cheap flights and hotels.",
"categories": ["travel", "education"],
"screenshots": [
{
"src": "screenshot.webp",
"sizes": "1280x720",
"type": "image/webp"
}
]
}
robots.txt:
User-agent: * Disallow: /api User-agent: Yandex Disallow: /api Clean-param: bonus&utm_source&utm_medium&utm_campaign&utm_term&utm_content&click_id&appstore&platform Host: https://buy-and-fly.fafn.ru Sitemap: https://buy-and-fly.fafn.ru/sitemap.xml
At the end we use the layout in src/app/app.routes.ts:
import { Routes } from '@angular/router';
export const routes: Routes = [
{
path: '',
loadComponent: () => import('@baf/ui/layout').then((m) => m.LayoutComponent),
children: [],
},
];
Launch the application:
yarn serve
We will see a white screen :)
Создадим шапку и подвал:
yarn ng g c header yarn ng g c footer
Перенесем в ui/layout и экспортируем:
export * from './lib/footer/footer.component'; export * from './lib/header/header.component'; export * from './lib/layout.component';
Подключим их в приложении:
import { Routes } from '@angular/router';
export const routes: Routes = [
{
path: '',
loadComponent: () => import('@baf/ui/layout').then((m) => m.LayoutComponent),
children: [
{
path: '',
loadComponent: () => import('@baf/ui/layout').then((m) => m.HeaderComponent),
outlet: 'header',
},
{
path: '',
loadComponent: () => import('@baf/ui/layout').then((m) => m.FooterComponent),
outlet: 'footer',
},
],
},
];
Запустим проект:
yarn serve
Видим созданные компоненты.
В следующей статье добавим core сервисы и интерфейсы.
Все исходники находятся на github, в репозитории - github.com/Fafnur/buy-and-fly
Демо можно посмотреть здесь - buy-and-fly.fafn.ru/
Мои группы: telegram, medium, vk, x.com, linkedin, site
The above is the detailed content of Creating a Basic Framework for Angular 18. For more information, please follow other related articles on the PHP Chinese website!