angular19-官方教程学习

news2025/3/1 9:18:06

周日了解到angular已经更新到19了,想按官方教程学习一遍,工欲善其事必先利其器,先更新工具:

安装新版版本

卸载老的nodejs 20.10.0,安装最新的LTS版本
https://nodejs.org
最新LTS版本已经是22.12.0
C:\Program Files\nodejs\ 目录改为 C:\nodejs\
PS C:\angular> node --version
v22.12.0
PS C:\angular> npm --version
10.9.0
重新更新angular
npm install -g @angular/cli
PS C:\angular> npm install -g @angular/cli

added 83 packages, removed 38 packages, and changed 189 packages in 23s

51 packages are looking for funding
  run `npm fund` for details
npm notice
npm notice New patch version of npm available! 10.9.0 -> 10.9.2
npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.9.2
npm notice To update run: npm install -g npm@10.9.2
npm notice
提示更新npm到最新版本,我就更新一下。
PS C:\angular> npm install -g npm@10.9.2

added 1 package in 8s

25 packages are looking for funding
  run `npm fund` for details
查看angular版本
PS C:\angular> ng version

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/


Angular CLI: 19.0.4
Node: 22.12.0
Package Manager: npm 10.9.2
OS: win32 x64

Angular:
...

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.1900.4 (cli-only)
@angular-devkit/core         19.0.4 (cli-only)
@angular-devkit/schematics   19.0.4 (cli-only)
@schematics/angular          19.0.4 (cli-only)
已经是19.0.4最新版本了,完美。

教程学习

开始学习最新教程:
https://angular.dev/tutorials/first-app

https://www.youtube.com/watch?v=xAT0lHYhHMY&t=148s  教程
Download the code →https://goo.gle/learn-angular-step-1 

他这个版本是angular15的,不能直接用,进入目录后npm install, 这个是根据package.json里面的版本信息安装。

我直接建立一个
ng new angular.io-example
 

PS C:\angular> ng new angular.io-example
✔ Which stylesheet format would you like to use? CSS             [ https://developer.mozilla.org/docs/Web/CSS
          ]
✔ Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? No
CREATE angular.io-example/angular.json (2734 bytes)
CREATE angular.io-example/package.json (1087 bytes)
CREATE angular.io-example/README.md (1538 bytes)
CREATE angular.io-example/tsconfig.json (942 bytes)
CREATE angular.io-example/.editorconfig (331 bytes)
CREATE angular.io-example/.gitignore (629 bytes)
CREATE angular.io-example/tsconfig.app.json (439 bytes)
CREATE angular.io-example/tsconfig.spec.json (449 bytes)
CREATE angular.io-example/.vscode/extensions.json (134 bytes)
CREATE angular.io-example/.vscode/launch.json (490 bytes)
CREATE angular.io-example/.vscode/tasks.json (980 bytes)
CREATE angular.io-example/src/main.ts (256 bytes)
CREATE angular.io-example/src/index.html (315 bytes)
CREATE angular.io-example/src/styles.css (81 bytes)
CREATE angular.io-example/src/app/app.component.html (20239 bytes)
CREATE angular.io-example/src/app/app.component.spec.ts (981 bytes)
CREATE angular.io-example/src/app/app.component.ts (306 bytes)
CREATE angular.io-example/src/app/app.component.css (0 bytes)
CREATE angular.io-example/src/app/app.config.ts (318 bytes)
CREATE angular.io-example/src/app/app.routes.ts (80 bytes)
CREATE angular.io-example/public/favicon.ico (15086 bytes)
✔ Packages installed successfully.
Author identity unknown

试试能否运行:ng serve

PS C:\angular\angular.io-example> ng serve
Initial chunk files | Names         |  Raw size
polyfills.js        | polyfills     |  90.20 kB |
main.js             | main          |  18.19 kB |
styles.css          | styles        |  95 bytes |

                    | Initial total | 108.48 kB

Application bundle generation complete. [7.280 seconds]

Watch mode enabled. Watching for file changes...
NOTE: Raw file sizes do not reflect development server per-request transformations.
  ➜  Local:   http://localhost:4200/
  ➜  press h + enter to show help

1.create Hello World

https://angular.dev/tutorials/first-app/01-hello-world

  1. Open first-app/src/index.html. Note: This step and the next are only for your local environment!

  2. In index.html, replace the <title> element with this code to update the title of the app.

<title>Homes</title>

3.Next, open first-app/src/app/app.component.ts.

import {Component} from '@angular/core';
@Component({
  selector: 'app-root',
  imports: [],
  template: `
    <h1>Hello world!</h1>
  `,
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  title = 'homes';
}

这样就能正确显示Hello World了

2. Create Home Component

ng generate component home

看了视频,与网页教程有区别,增加了两个参数:

ng generate component Home --standalone --inline-template

template就不会单独存储到html中了,放到ts文件中,对于小的组件确实方便。

PS C:\angular\angular.io-example> ng generate component home
CREATE src/app/home/home.component.html (20 bytes)
CREATE src/app/home/home.component.spec.ts (601 bytes)
CREATE src/app/home/home.component.ts (217 bytes)
CREATE src/app/home/home.component.css (0 bytes)

把Home组件增加到app中:

In app.component.ts, import HomeComponent by adding this line to the file level imports

import {HomeComponent} from './home/home.component';

In app.component.ts, in @Component, update the imports array property and add HomeComponent.

import {Component} from '@angular/core';
import {HomeComponent} from './home/home.component';
@Component({
  selector: 'app-root',
  imports: [HomeComponent],
  template: `
    <main>
      <header class="brand-name">
        <img class="brand-logo" src="/assets/logo.svg" alt="logo" aria-hidden="true" />
      </header>
      <section class="content">
        <app-home></app-home>
      </section>
    </main>
  `,
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  title = 'homes';
}

发现logo.svg没有加载,下载上面链接中的例子,发现多了一个asset文件夹,拷贝到我自己的项目src目录下,还是提示404,最后发现angular.json中要定义这个asset

            "tsConfig": "tsconfig.app.json",
            "assets": [
                "src/favicon.ico",
                "src/assets"
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": []

增加后可以正常显示图标和home组件了。

3. Add feature to Home Component

Replace in src/app/home/home.component.ts

import {Component} from '@angular/core';
import {CommonModule} from '@angular/common';
@Component({
  selector: 'app-home',
  imports: [CommonModule],
  template: `
    <section>
      <form>
        <input type="text" placeholder="Filter by city" />
        <button class="primary" type="button">Search</button>
      </form>
    </section>
  `,
  styleUrls: ['./home.component.css'],
})
export class HomeComponent {}

home.component.css 修改style

.results {
  display: grid;
  column-gap: 14px;
  row-gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(400px, 400px));
  margin-top: 50px;
  justify-content: space-around;
}
input[type="text"] {
  border: solid 1px var(--primary-color);
  padding: 10px;
  border-radius: 8px;
  margin-right: 4px;
  display: inline-block;
  width: 30%;
}
button {
  padding: 10px;
  border: solid 1px var(--primary-color);
  background: var(--primary-color);
  color: white;
  border-radius: 8px;
}
@media (min-width: 500px) and (max-width: 768px) {
  .results {
      grid-template-columns: repeat(2, 1fr);
  }
  input[type="text"] {
      width: 70%;
  }   
}
@media (max-width: 499px) {
  .results {
      grid-template-columns: 1fr;
  }    
}

修改样式后发现按钮显示不出来了,把根目录的样式文件也改一下:styles.css

/* You can add global styles to this file, and also import other style files */
* {
    margin: 0;
    padding: 0;
  }
  
  body {
    font-family: 'Be Vietnam Pro', sans-serif;
  }
  :root {
    --primary-color: #605DC8;
    --secondary-color: #8B89E6;
    --accent-color: #e8e7fa;
    --shadow-color: #E8E8E8;
  }
  
  button.primary {
    padding: 10px;
    border: solid 1px var(--primary-color);
    background: var(--primary-color);
    color: white;
    border-radius: 8px;
  }
  

这就可以显示一个搜索框和按钮了:

4. create the application's HousingLocation component

ng generate component housingLocation --standalone --inline-template

PS C:\angular\angular.io-example> ng generate component housingLocation --standalone --inline-template
CREATE src/app/housing-location/housing-location.component.spec.ts (679 bytes)
CREATE src/app/housing-location/housing-location.component.ts (282 bytes)
CREATE src/app/housing-location/housing-location.component.css (0 bytes)

Add the new component to your app's layout

Import HousingLocationComponent in src/app/home/home.component.ts

import {HousingLocationComponent} from '../housing-location/housing-location.component';

Add HousingLocationComponent to imports array in src/app/home/home.component.ts

import {Component} from '@angular/core';
import {CommonModule} from '@angular/common';
import {HousingLocationComponent} from '../housing-location/housing-location.component';
@Component({
  selector: 'app-home',
  imports: [CommonModule, HousingLocationComponent],
  template: `
    <section>
      <form>
        <input type="text" placeholder="Filter by city" />
        <button class="primary" type="button">Search</button>
      </form>
    </section>
    <section class="results">
      <app-housing-location></app-housing-location>
    </section>
  `,
  styleUrls: ['./home.component.css'],
})
export class HomeComponent {}

增加housing-location组件的style:

.listing {
  background: var(--accent-color);
  border-radius: 30px;
  padding-bottom: 30px;
}
.listing-heading {
  color: var(--primary-color);
  padding: 10px 20px 0 20px;
}
.listing-photo {
  height: 250px;
  width: 100%;
  object-fit: cover;
  border-radius: 30px 30px 0 0;
}
.listing-location {
  padding: 10px 20px 20px 20px;
}
.listing-location::before {
  content: url("/assets/location-pin.svg") / "";
}
section.listing a {
  padding-left: 20px;
  text-decoration: none;
  color: var(--primary-color);
}
section.listing a::after {
  content: "\203A";
  margin-left: 5px;
}

5. Creating an interface

ng generate interface housingLocation

PS C:\angular\angular.io-example> ng generate interface housingLocation
CREATE src/app/housing-location.ts (39 bytes)

增加interface的内容

export interface HousingLocation {
  id: number;
  name: string;
  city: string;
  state: string;
  photo: string;
  availableUnits: number;
  wifi: boolean;
  laundry: boolean;
}

6. Create a test house for your app

Import HomeComponent in src/app/home/home.component.ts

import {HousingLocation} from '../housinglocation';

In src/app/home/home.component.ts, replace the empty export class HomeComponent {} definition with this code to create a single instance of the new interface in the component.

readonly baseUrl = 'https://angular.dev/assets/images/tutorials/common';
  housingLocation: HousingLocation = {
    id: 9999,
    name: 'Test Home',
    city: 'Test city',
    state: 'ST',
    photo: `${this.baseUrl}/example-house.jpg`,
    availableUnits: 99,
    wifi: true,
    laundry: false,
  };
}

7. Add an input parameter to the component

Import HousingLocationComponent and Input in src/app/housing-location/housing-location.component.ts

import {Component, Input} from '@angular/core';
import {CommonModule} from '@angular/common';
import {HousingLocation} from '../housinglocation';

input

import {Component, Input} from '@angular/core';
import {CommonModule} from '@angular/common';
import {HousingLocation} from '../housinglocation';
@Component({
  selector: 'app-housing-location',
  imports: [CommonModule],
  template: `
    <p>housing-location works!</p>
  `,
  styleUrls: ['./housing-location.component.css'],
})
export class HousingLocationComponent {
  @Input() housingLocation!: HousingLocation;
}

其中的!表示必须非空。

8. Add a property binding to a component's template

Your app has data bindings in the HomeComponent template.
Your app sends data from the HomeComponent to the HousingLocationComponent.

数据绑定,数据在组件间通过Input传递

Add housingLocation property binding

<app-housing-location [housingLocation]="housingLocation"></app-housing-location>
    </section>
  `,

9. Add an interpolation(插值) to a component's template

Your app will display interpolated values in the HousingLocationComponent template.
Your app will render a housing location data to the browser.
增加插值;渲染数据;

Using the {{ expression }} in Angular templates

Update HousingLocationComponent template

<section class="listing">
      <img
        class="listing-photo"
        [src]="housingLocation.photo"
        alt="Exterior photo of {{ housingLocation.name }}"
        crossorigin
      />
      <h2 class="listing-heading">{{ housingLocation.name }}</h2>
      <p class="listing-location">{{ housingLocation.city }}, {{ housingLocation.state }}</p>
    </section>
  `,
  styleUrls: ['./housing-location.component.css'],

其中的alt在图片无法加载时显示的信息。

这时已经可以多组件传递interface,并显示结果了:

10. Use *ngFor to list objects in components

使用循环显示列表

Add housing data to the HomeComponent  这次是增加多条数据了

src/app/home/home.component.ts

import {Component} from '@angular/core';
import {CommonModule} from '@angular/common';
import {HousingLocationComponent} from '../housing-location/housing-location.component';
import {HousingLocation} from '../housinglocation';
@Component({
  selector: 'app-home',
  imports: [CommonModule, HousingLocationComponent],
  template: `
    <section>
      <form>
        <input type="text" placeholder="Filter by city" />
        <button class="primary" type="button">Search</button>
      </form>
    </section>
    <section class="results">
      <app-housing-location
        *ngFor="let housingLocation of housingLocationList"
        [housingLocation]="housingLocation"
      ></app-housing-location>
    </section>
  `,
  styleUrls: ['./home.component.css'],
})
export class HomeComponent {
  readonly baseUrl = 'https://angular.dev/assets/images/tutorials/common';
  housingLocationList: HousingLocation[] = [
    {
      id: 0,
      name: 'Acme Fresh Start Housing',
      city: 'Chicago',
      state: 'IL',
      photo: `${this.baseUrl}/bernard-hermant-CLKGGwIBTaY-unsplash.jpg`,
      availableUnits: 4,
      wifi: true,
      laundry: true,
    },
    {
      id: 1,
      name: 'A113 Transitional Housing',
      city: 'Santa Monica',
      state: 'CA',
      photo: `${this.baseUrl}/brandon-griggs-wR11KBaB86U-unsplash.jpg`,
      availableUnits: 0,
      wifi: false,
      laundry: true,
    },
    {
      id: 2,
      name: 'Warm Beds Housing Support',
      city: 'Juneau',
      state: 'AK',
      photo: `${this.baseUrl}/i-do-nothing-but-love-lAyXdl1-Wmc-unsplash.jpg`,
      availableUnits: 1,
      wifi: false,
      laundry: false,
    },
    {
      id: 3,
      name: 'Homesteady Housing',
      city: 'Chicago',
      state: 'IL',
      photo: `${this.baseUrl}/ian-macdonald-W8z6aiwfi1E-unsplash.jpg`,
      availableUnits: 1,
      wifi: true,
      laundry: false,
    },
    {
      id: 4,
      name: 'Happy Homes Group',
      city: 'Gary',
      state: 'IN',
      photo: `${this.baseUrl}/krzysztof-hepner-978RAXoXnH4-unsplash.jpg`,
      availableUnits: 1,
      wifi: true,
      laundry: false,
    },
    {
      id: 5,
      name: 'Hopeful Apartment Group',
      city: 'Oakland',
      state: 'CA',
      photo: `${this.baseUrl}/r-architecture-JvQ0Q5IkeMM-unsplash.jpg`,
      availableUnits: 2,
      wifi: true,
      laundry: true,
    },
    {
      id: 6,
      name: 'Seriously Safe Towns',
      city: 'Oakland',
      state: 'CA',
      photo: `${this.baseUrl}/phil-hearing-IYfp2Ixe9nM-unsplash.jpg`,
      availableUnits: 5,
      wifi: true,
      laundry: true,
    },
    {
      id: 7,
      name: 'Hopeful Housing Solutions',
      city: 'Oakland',
      state: 'CA',
      photo: `${this.baseUrl}/r-architecture-GGupkreKwxA-unsplash.jpg`,
      availableUnits: 2,
      wifi: true,
      laundry: true,
    },
    {
      id: 8,
      name: 'Seriously Safe Towns',
      city: 'Oakland',
      state: 'CA',
      photo: `${this.baseUrl}/saru-robert-9rP3mxf8qWI-unsplash.jpg`,
      availableUnits: 10,
      wifi: false,
      laundry: false,
    },
    {
      id: 9,
      name: 'Capital Safe Towns',
      city: 'Portland',
      state: 'OR',
      photo: `${this.baseUrl}/webaliser-_TPTXZd9mOo-unsplash.jpg`,
      availableUnits: 6,
      wifi: true,
      laundry: true,
    },
  ];
}

ngfor:

<app-housing-location
        *ngFor="let housingLocation of housingLocationList"
        [housingLocation]="housingLocation"
      ></app-housing-location>
    </section>
  `,

奇怪的时housing-location.component.ts里面的内容不需要动,就能显示列表了。这是为啥?

显示效果如下:

11. Add routes to the Application

main.ts  增加:

import { provideRouter } from '@angular/router';

bootstrapApplication(AppComponent  增加数组

import { provideRouter } from '@angular/router';

bootstrapApplication(AppComponent, {
  providers: [],
}).catch((err) => console.error(err));

新建 routes.ts

import {Routes} from '@angular/router';
import { HomeComponent } from './app/home/home.component';

const routeConfig: Routes = [];

export default routeConfig;

还没有路由,继续:

app.component.ts

import { RouterModule } from '@angular/router';

imports: [ HomeComponent,RouterModule ],

<app-home></app-home> 这种直接引用 home component改为路由

<router-outlet></router-outlet>

这时屏幕就显示一个白板了,因为还没有路由

在routes.ts中增加路由

const routeConfig: Routes = [
    {
        path: '',
        component: HomeComponent,
        title: 'Home page',
    },
];

在main.ts中引入这个routeConfig

import routeConfig from './routes';

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(routeConfig)
  ],
}).catch((err) => console.error(err));

现在功能恢复正常。这样路由配置就加上了。

12 增加 详情组件

ng g c details --standalone --inline-template

ng g c details --standalone --inline-template
CREATE src/app/details/details.component.spec.ts (622 bytes)
CREATE src/app/details/details.component.ts (247 bytes)
CREATE src/app/details/details.component.css (0 bytes)

然后增加详情的路由routes.ts

import { DetailsComponent } from './app/details/details.component';

    {
        path: 'details/:id',
        component: DetailsComponent,
        title: 'Home details',
    },

在housing-location.ts中增加

首先引入RouteModule,然后加上路由链接。

import {RouterModule} from '@angular/router';

imports: [RouterModule],

<a [routerLink]="['/details', housingLocation.id]">Learn More</a>

这样这个detail组件就集成到链接中了。

其中routeLinker加了方括号,说明后面时个动态的值,里面传递了参数id.可以用如下形式访问:

localhost:4200/details/2

相应的routes.ts中也要体现这种动态路由:/details/:id

这个id传递过去后,detail组件要从route中接收,需要引入ActivatedRoute

details.components.ts中增加

import { Component, inject } from '@angular/core';
import {ActivatedRoute} from '@angular/router';

  template: `
    <p>
      details works! {{housingLocationId}}
    </p>

route: ActivatedRoute = inject(ActivatedRoute);
housingLocationId = 0;

constructor() {
    this.housingLocationId = Number(this.route.snapshot.params['id']);
}

这样可以点击到详情可以显示id

13 增加service,并进行依赖注入,用于访问数据

ng g s housing

PS C:\angular\angular.io-example> ng g s housing
CREATE src/app/housing.service.spec.ts (378 bytes)
CREATE src/app/housing.service.ts (145 bytes)

把HousingLocation组件的数据部分挪到这个service中。并增加了两个查找方法,一个全部查找,一个根据id查找。

import { Injectable } from '@angular/core';
import { HousingLocation } from './housing-location';

@Injectable({
  providedIn: 'root'
})
export class HousingService {
  readonly baseUrl = 'https://angular.dev/assets/images/tutorials/common';
  protected housingLocationList: HousingLocation[] = [
    {
      id: 0,
      name: 'Acme Fresh Start Housing',
      city: 'Chicago',
      state: 'IL',
      photo: `${this.baseUrl}/bernard-hermant-CLKGGwIBTaY-unsplash.jpg`,
      availableUnits: 4,
      wifi: true,
      laundry: true,
    },
    {
      id: 1,
      name: 'A113 Transitional Housing',
      city: 'Santa Monica',
      state: 'CA',
      photo: `${this.baseUrl}/brandon-griggs-wR11KBaB86U-unsplash.jpg`,
      availableUnits: 0,
      wifi: false,
      laundry: true,
    },
    {
      id: 2,
      name: 'Warm Beds Housing Support',
      city: 'Juneau',
      state: 'AK',
      photo: `${this.baseUrl}/i-do-nothing-but-love-lAyXdl1-Wmc-unsplash.jpg`,
      availableUnits: 1,
      wifi: false,
      laundry: false,
    },
    {
      id: 3,
      name: 'Homesteady Housing',
      city: 'Chicago',
      state: 'IL',
      photo: `${this.baseUrl}/ian-macdonald-W8z6aiwfi1E-unsplash.jpg`,
      availableUnits: 1,
      wifi: true,
      laundry: false,
    },
    {
      id: 4,
      name: 'Happy Homes Group',
      city: 'Gary',
      state: 'IN',
      photo: `${this.baseUrl}/krzysztof-hepner-978RAXoXnH4-unsplash.jpg`,
      availableUnits: 1,
      wifi: true,
      laundry: false,
    },
    {
      id: 5,
      name: 'Hopeful Apartment Group',
      city: 'Oakland',
      state: 'CA',
      photo: `${this.baseUrl}/r-architecture-JvQ0Q5IkeMM-unsplash.jpg`,
      availableUnits: 2,
      wifi: true,
      laundry: true,
    },
    {
      id: 6,
      name: 'Seriously Safe Towns',
      city: 'Oakland',
      state: 'CA',
      photo: `${this.baseUrl}/phil-hearing-IYfp2Ixe9nM-unsplash.jpg`,
      availableUnits: 5,
      wifi: true,
      laundry: true,
    },
    {
      id: 7,
      name: 'Hopeful Housing Solutions',
      city: 'Oakland',
      state: 'CA',
      photo: `${this.baseUrl}/r-architecture-GGupkreKwxA-unsplash.jpg`,
      availableUnits: 2,
      wifi: true,
      laundry: true,
    },
    {
      id: 8,
      name: 'Seriously Safe Towns',
      city: 'Oakland',
      state: 'CA',
      photo: `${this.baseUrl}/saru-robert-9rP3mxf8qWI-unsplash.jpg`,
      availableUnits: 10,
      wifi: false,
      laundry: false,
    },
    {
      id: 9,
      name: 'Capital Safe Towns',
      city: 'Portland',
      state: 'OR',
      photo: `${this.baseUrl}/webaliser-_TPTXZd9mOo-unsplash.jpg`,
      availableUnits: 6,
      wifi: true,
      laundry: true,
    },
  ];

  getAllHousingLocations() : HousingLocation[] {
    return this.housingLocationList;
  }

  getHousingLocationById(id: Number): HousingLocation | undefined {
    return this.housingLocationList.find(
      housingLocation => housingLocation.id === id
    );
  }

  constructor() { }
}

Home组件取数据的方法加上。注入service,然后取service中的数据。

import { Component,inject } from '@angular/core';
import { HousingService } from '../housing.service';

export class HomeComponent {
  housingLocationList: HousingLocation[] = [];
  housingService: HousingService = inject(HousingService);
  
  constructor() {
    this.housingLocationList = this.housingService.getAllHousingLocations();
  }
}

功能恢复运行!

14. 完善详情页

details.component.ts  注入service,引用HousingLocation,通过service经过参数ID查询到HousingLocation对象。

import { Component, inject } from '@angular/core';

import {HousingService} from '../housing.service';
import { HousingLocation } from '../housing-location';

  template: `
    <p>
      details works! {{housingLocation?.id}}
    </p>
  `,

export class DetailsComponent {

  housingService = inject(HousingService);
  housingLocation: HousingLocation | undefined;

  constructor() {
    const housingLocationId = Number(this.route.snapshot.params['id']);
    this.housingLocation = this.housingService.getHousingLocationById(housingLocationId);
  }

再完善一下显示模板

  template: `
    <article>
    <img
        class="listing-photo"
        [src]="housingLocation?.photo"
        alt="Exterior photo of {{ housingLocation?.name }}"
        crossorigin
      />
      <section class="listing-description">
        <h2 class="listing-heading">{{ housingLocation?.name }}</h2>
        <p class="listing-location">{{ housingLocation?.city }}, {{ housingLocation?.state }}</p>
      </section>
      <section class="listing-features">
        <h2 class="section-heading">About this housing location</h2>
        <ul>
          <li>Units available: {{ housingLocation?.availableUnits }}</li>
          <li>Does this location have wifi: {{ housingLocation?.wifi }}</li>
          <li>Does this location have laundry: {{ housingLocation?.laundry }}</li>
        </ul>
      </section>
    </article>
  `,

增加CSS

.listing-photo {
    height: 600px;
    width: 50%;
    object-fit: cover;
    border-radius: 30px;
    float: right;
  }
  .listing-heading {
    font-size: 48pt;
    font-weight: bold;
    margin-bottom: 15px;
  }
  .listing-location::before {
    content: url('/assets/location-pin.svg') / '';
  }
  .listing-location {
    font-size: 24pt;
    margin-bottom: 15px;
  }
  .listing-features > .section-heading {
    color: var(--secondary-color);
    font-size: 24pt;
    margin-bottom: 15px;
  }
  .listing-features {
    margin-bottom: 20px;
  }
  .listing-features li {
    font-size: 14pt;
  }
  li {
    list-style-type: none;
  }
  .listing-apply .section-heading {
    font-size: 18pt;
    margin-bottom: 15px;
  }
  label, input {
    display: block;
  }
  label {
    color: var(--secondary-color);
    font-weight: bold;
    text-transform: uppercase;
    font-size: 12pt;
  }
  input {
    font-size: 16pt;
    margin-bottom: 15px;
    padding: 10px;
    width: 400px;
    border-top: none;
    border-right: none;
    border-left: none;
    border-bottom: solid .3px;
  }
  @media (max-width: 1024px) {
    .listing-photo {
      width: 100%;
      height: 400px;
    }
  }

这样详情就更新完成了。

视频中还有一个apply按钮,估计是预定这个房子:

      <section class="listing-apply">
        <h2 clas="section-heading">Apply now to live here</h2>
        <button class="primary" type="button">Apply now</button>
      </section>

基本功能完成。后面还有2个视频,分别是form表单,还有就是增加search房子的功能。

太困了,明天上班,未完待续吧。。。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2259104.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机毕业设计Python+Vue.js游戏推荐系统 Steam游戏推荐系统 Django Flask 游 戏可视化 游戏数据分析 游戏大数据 爬虫 机

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

上海亚商投顾:创业板指震荡调整 机器人概念股再度爆发

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日冲高回落&#xff0c;深成指、创业板指盘中跌超1%&#xff0c;尾盘跌幅有所收窄。机器人概念股逆势爆…

粘贴可运行:Java调用大模型(LLM) 流式Flux stream 输出;基于spring ai alibaba

在Java中&#xff0c;使用Spring AI Alibaba框架调用国产大模型通义千问&#xff0c;实现流式输出&#xff0c;是一种高效的方式。通过Spring AI Alibaba&#xff0c;开发者可以轻松地集成通义千问模型&#xff0c;并利用其流式处理能力&#xff0c;实时获取模型生成的文本。这…

【CSS in Depth 2 精译_070】11.3 利用 OKLCH 颜色值来处理 CSS 中的颜色问题(下):从页面其他颜色衍生出新颜色

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第四部分 视觉增强技术 ✔️【第 11 章 颜色与对比】 ✔️ 11.1 通过对比进行交流 11.1.1 模式的建立11.1.2 还原设计稿 11.2 颜色的定义 11.2.1 色域与色彩空间11.2.2 CSS 颜色表示法 11.2.2.1 RGB…

Ajax--实现检测用户名是否存在功能

目录 &#xff08;一&#xff09;什么是Ajax &#xff08;二&#xff09;同步交互与异步交互 &#xff08;三&#xff09;AJAX常见应用情景 &#xff08;四&#xff09;AJAX的优缺点 &#xff08;五&#xff09;使用jQuery实现AJAX 1.使用JQuery中的ajax方法实现步骤&#xf…

【PSINS】以速度和位置作为观测量(即6维观测量)的组合导航滤波,EKF实现,提供可直接运行的MATLAB代码

原有的代码是以位置作为观测量的,这里提供位置+速度,共6维的观测量,状态量还是15维不变 文章目录 源代码运行结果PS源代码 源代码如下: % 【PSINS】位置与速度为观测的153,EKF。从速度观测的EKF153改进而来 % 2024-12-11/Ver1:位置与速度为观测量% 清空工作空间,清除命…

探索云原生安全解决方案的未来

我们是否充分意识到云端所面临的网络安全威胁&#xff1f; 在当今互联互通的世界中&#xff0c;维护安全的环境至关重要。云的出现扩大了潜在威胁的范围&#xff0c;因为它催生了机器身份&#xff08;称为非人类身份 (NHI)&#xff09;及其秘密。随着组织越来越多地转向云原生…

无法正常启动此程序,因为计算机丢失wlanapi.dll

wlanapi.dll丢失怎么办&#xff1f;有没有什么靠谱的修复wlanapi.dll方法_无法启动此程序,因为计算机中丢失wlanapi.dll-CSDN博客 wlanapi.dll是 Windows 操作系统中的一个动态链接库文件&#xff0c;主要与 Windows 无线 LAN (WLAN) API 相关。该DLL提供了许多必要的函数&…

ADC -DMA

文章目录 前言一、ADC配置修改二、配置DMA三、DMA中断四、完整参考代码总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 项目需要&#xff1a; 在原有基础上改进&#xff0c;采用DMA中断采集数据 提示&#xff1a;以下是本篇文章正文内容&#xff0…

Referer头部在网站反爬虫技术中的运用

网站数据的安全性和完整性至关重要。爬虫技术&#xff0c;虽然在数据收集和分析中发挥着重要作用&#xff0c;但也给网站管理员带来了挑战。为了保护网站数据不被恶意爬取&#xff0c;反爬虫技术应运而生。本文将探讨HTTP头部中的Referer字段在反爬虫技术中的应用&#xff0c;并…

docker搭建haproxy实现负载均衡

华子目录 获取haproxy镜像建立haproxy容器的数据卷获取haproxy的配置文件编写yaml文件运行测试 获取haproxy镜像 [rootdocker-node1 ~]# docker pull haproxy:2.3建立haproxy容器的数据卷 conf目录为数据卷 [rootdocker-node1 ~]# mkdir /var/lib/docker/volumes/conf/获取h…

阿里云数据库MongoDB版助力极致游戏高效开发

客户简介 成立于2010年的厦门极致互动网络技术股份有限公司&#xff08;以下简称“公司”或“极致游戏”&#xff09;&#xff0c;是一家集网络游戏产品研发与运营为一体的重点软件企业&#xff0c;公司专注于面向全球用户的网络游戏研发与运营。在整个产业链中&#xff0c;公…

深入探索前端调试神器vConsole

深入探索前端调试神器vConsole 在前端开发过程中&#xff0c;调试工具的重要性不言而喻。而vConsole作为一款轻量级的、可嵌入的JavaScript调试面板&#xff0c;为前端开发者提供了一个便捷的调试解决方案。本文将带你深入了解vConsole的基本概念、作用&#xff0c;并通过丰富…

子网划分实例

看到有人问这个问题&#xff1a; 想了一下&#xff0c;这是一个子网划分的问题&#xff1a; 处理方法如图&#xff1a; 这是一个子网划分的问题 设备1用三层交换机&#xff0c;端口设置为路由模式&#xff0c;设备2和设备3为傻瓜交换机模式 设备2和设备3下挂设备都是26为掩码&…

【机器人】振动分析和控制工具之Bode图

Bode 图完整介绍 Bode 图由两个部分组成&#xff1a; 幅值图 (Magnitude Plot)&#xff1a;描述系统对不同频率输入信号的增益大小&#xff08;幅值响应&#xff09;。相位图 (Phase Plot)&#xff1a;描述系统输出信号相对于输入信号的相位差。 Bode 图的横轴是频率&#x…

Rerender A Video 技术浅析(五):对象移除与自动配色

Rerender A Video 是一种基于深度学习和计算机视觉技术的视频处理工具&#xff0c;旨在通过智能算法对视频进行重新渲染和优化。 一、对象移除模块 1. 目标检测 1.1 概述 目标检测是对象移除的第一步&#xff0c;旨在识别视频中需要移除的对象并生成相应的掩码&#xff08;m…

经典的网络安全技术

以我的理解&#xff0c;“黑客”大体上应该分为“正”、“邪”两类&#xff0c;正派黑客依靠自己掌握的知识帮助系统管理员找出系统中的漏洞并加以完善&#xff0c;而邪派黑客则是通过各种黑客技能对系统进行攻击、入侵或者做其他一些有害于网络的事情&#xff0c;因为邪派黑客…

Figma入门-实战列表页

Figma入门-实战列表页 前言 在之前的工作中&#xff0c;大家的原型图都是使用 Axure 制作的&#xff0c;印象中 Figma 一直是个专业设计软件。 最近&#xff0c;很多产品朋友告诉我&#xff0c;很多原型图都开始用Figma制作了&#xff0c;并且很多组件都是内置的&#xff0c…

什么是Apache日志?为什么Apache日志分析很重要?

Apache是全球最受欢迎的Web服务器软件&#xff0c;支持约30.2%的所有活跃网站。凭借其可靠性、灵活性和强大的功能&#xff0c;Apache数十年来一直是互联网的中坚力量。 一、Apache Web服务器的工作原理 Apache Web服务器的工作原理如下&#xff1a; 接收HTTP请求&#xff1…

基于Mybatis,MybatisPlus实现数据库查询分页功能

基于Mybatis&#xff0c;MybatisPlus实现数据库查询分页功能 目录 基于Mybatis&#xff0c;MybatisPlus实现数据库查询分页功能使用Mybatis插件实现分页数据库准备分页插件配置和使用常用数据&#xff1a; 使用MybatisPlus插件实现分页数据库准备分页插件配置和使用自定义分页查…