一,准备阶段。
初始化项目,并尝试运行:
ng new myProject
cd myProject
ng serve
二,添加外部框架:
npm install jquery --save
npm install popper.js --save
npm install bootstrap --save
由于typescript不能直接识别js,需要引入类型描述文件
npm i @types/jquery --save
![](https://i-blog.csdnimg.cn/blog_migrate/c0d16e8b5e456be90b4a13a36f9dd4e3.png)
文件会下载到node_modules文件夹
然后在package.json文件里添加进来:
手动在angular.json文件里,添加对js文件及css文件的引用:
三,新建组件
将需求内容分割成若干组件,然后新建这些组件。
使用命令
$ ng g component product
app文件夹内生成了相关组件文件夹,且app.module.ts内会自动引入新增组件
四,编写主组件
五,bootstrap相关代码
官方文档:
https://v4.bootcss.com/docs
导航:
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
<div class="container">
<a class="navbar-brand" href="#">导航栏</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#">Disabled</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</div>
</nav>
form表单:
<form>
<div class="form-group">
<label for="productTitle">商品名称</label>
<input type="email" class="form-control" id="productTitle" aria-describedby="emailHelp" placeholder="Enter email">
<!-- <small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small> -->
</div>
<div class="form-group">
<label for="productPrice">商品价格</label>
<input type="email" class="form-control" id="productPrice" aria-describedby="emailHelp" placeholder="Enter email">
<!-- <small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small> -->
</div>
<div class="form-group">
<label for="productCategory">商品类别</label>
<select id="productCategory" class="form-control" name="">
</select>
<!-- <small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small> -->
</div>
<!-- <div class="form-group">
<label for="exampleInputPassword1">Password</label>
<input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" id="exampleCheck1">
<label class="form-check-label" for="exampleCheck1">Check me out</label>
</div>
-->
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block">搜索</button>
</div>
</form>
轮播:
<div id="carouselExampleControls" class="carousel slide" data-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item active">
<img class="d-block w-100" src="../assets/img/1.jpg" alt="First slide">
<div class="carousel-caption d-none d-md-block">
<h5>大标题</h5>
<p>文本</p>
</div>
</div>
<div class="carousel-item">
<img class="d-block w-100" src="../assets/img/2.jpg" alt="Second slide">
<div class="carousel-caption d-none d-md-block">
<h5>大标题</h5>
<p>文本</p>
</div>
</div>
<div class="carousel-item">
<img class="d-block w-100" src="../assets/img/3.jpg" alt="Third slide">
<div class="carousel-caption d-none d-md-block">
<h5>大标题</h5>
<p>文本</p>
</div>
</div>
</div>
<a class="carousel-control-prev" href="#carouselExampleControls" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#carouselExampleControls" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
六,*ngFor遍历数组
product.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-product',
templateUrl: './product.component.html',
styleUrls: ['./product.component.css']
})
//控制器
export class ProductComponent implements OnInit {
// 一个Product的数组
private products:Array<Product>
constructor() { }
ngOnInit() {
this.products=[
new Product(1,"第一个商品",12.5,3.5,"商品描述",["书籍","java"]),
new Product(2,"第二个商品",12.5,4.5,"商品描述",["书籍","java"]),
new Product(3,"第三个商品",12.5,2.5,"商品描述",["书籍","java"]),
new Product(4,"第四个商品",12.5,4.5,"商品描述",["书籍","java"]),
new Product(5,"第五个商品",12.5,3.5,"商品描述",["书籍","java"]),
new Product(6,"第六个商品",12.5,4.5,"商品描述",["书籍","java"])
]
}
}
//用来描述商品信息的类
export class Product{
constructor(
public id:number,
public title:string,
public price:number,
public rating:number,
public desc:string,
public categories:Array<string>
){
}
}
product.component.html
<div class="row">
<div *ngFor="let product of products" class="col-md-4 col-sm-4 col-lg-4">
<div class="thumbnail">
<img src="//placehold.it/320x150" alt="">
<div class="caption">
<h4 class="pull-right">1{{product.price}}</h4>
<h4><a href="#">1{{product.title}}</a> </h4>
<p>1{{product.desc}}</p>
</div>
</div>
</div>
</div>
核心代码:
*ngFor="let product of products"
再利用插值表达式将数据插入。
七,指令变更
双向绑定:
[(ngModel)]
<div><input type="text" [(ngModel)]="hero">
<p>{{hero}}</p></div>
需要引入FormsMudule
打开 AppModule (app.module.ts) 并从 @angular/forms 库中导入 FormsModule 符号。
import { FormsModule } from '@angular/forms';
imports: [
BrowserModule,
FormsModule
],
路径绑定:
网上方法不一,其实直接使用差值表达式即可:
src="{{carousel.url}}"
<div *ngFor="let carousel of carousels" class="carousel-item">
<img class="d-block w-100" src="{{carousel.url}}" alt="Second slide">
<div class="carousel-caption d-none d-md-block">
<h5>{{carousel.title}}</h5>
<p>{{carousel.desc}}</p>
</div>
</div>
[hero]="selectedHero"
Angular 的属性绑定语法
点击事件:
(click)
<div *ngFor="let hero of heroes" (click)="onSelect(hero)">
{{hero.name | uppercase}}
{{hero.id}}
</div>
定义函数:
onSelect(hero:Hero):void {
alert(hero.name)
// this.selecteHero = hero;
}
class绑定:
<div *ngFor="let hero of heroes" [class.selected]="hero === selectedHero" (click)="onSelect(hero)" >
{{hero.name | uppercase}}
{{hero.id}}
</div>
onSelect(hero:Hero):void {
this.selectedHero = hero;
}
当当前对象等于selectedHero中绑定的对象的时候,[class.selected]有效
*ngIf
<div *ngIf="selectedHero">
<h2>{{ selectedHero.name | uppercase }} Details</h2>
<div><span>id: </span>{{selectedHero.id}}</div>
<div>
<label>name:
<input [(ngModel)]="selectedHero.name" placeholder="name">
</label>
</div>
</div>
根据selectedHero值,显示数组对象。
八,类的创建及引入
src/app/hero.ts
export class Hero {
id: number;
name: string;
}
src/app/heroes/heroes.component.ts 引入:
import { Hero } from '../hero';
类中存储的数据:
基于hero.ts中Hero类各项属性设定,所以也需要引入hero.ts。
src/app/mock-heroes.ts
import { Hero } from './hero';
export const HEROES: Hero[] = [
{ id: 11, name: 'Mr. Nice' },
{ id: 12, name: 'Narco' },
{ id: 13, name: 'Bombasto' },
{ id: 14, name: 'Celeritas' },
{ id: 15, name: 'Magneta' },
{ id: 16, name: 'RubberMan' },
{ id: 17, name: 'Dynama' },
{ id: 18, name: 'Dr IQ' },
{ id: 19, name: 'Magma' },
{ id: 20, name: 'Tornado' }
];
引入数据:
src/app/heroes/heroes.component.ts (import HEROES)
import { HEROES } from '../mock-heroes';
使用数据:
export class HeroesComponent implements OnInit {
heroes = HEROES;
constructor() { }
ngOnInit() {
}
}
九,主从组件
1,添加新组件
2,编写模板
<div *ngIf="hero">
<h2>{{ hero.name | uppercase }} Details</h2>
<div><span>id: </span>{{hero.id}}</div>
<div>
<label>name:
<input [(ngModel)]="hero.name" placeholder="name">
</label>
</div>
</div>
3,添加 @Input() hero 属性
修改 @angular/core 的导入语句,导入 Input 符号。
import { Component, OnInit ,Input} from '@angular/core';
import { Hero } from '../hero';
添加一个带有 @Input() 装饰器的 hero 属性。
export class HeroDetailComponent implements OnInit {
@Input() hero: Hero;
constructor() { }
ngOnInit() {
}
}
4,在父组件中使用
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
[hero]="selectedHero" 是 Angular 的属性绑定语法。这是一种单向数据绑定。
从父组件的 selectedHero 属性绑定到目标元素的 hero 属性,并映射到了子组件的 hero 属性。
参考地址:https://www.angular.cn/tutorial/toh-pt3#write-the-template
十,service
1,创建:
ng generate service hero
2,获取数据:
导入 Hero(属性设定) 和 HEROES(模拟数据)。
import { Hero } from './hero';
import { HEROES } from './mock-heroes';
3,创建方法用来返回数据:
添加一个 getHeroes 方法,让它返回模拟的英雄列表。
getHeroes(): Hero[] {
return HEROES;
}
4,提供服务( HeroService)
可以在安装的时候:
ng generate service hero --module=app
或者手动提供:
打开 AppModule 类,导入 HeroService,并把它加入 @NgModule.providers 数组中。
import { HeroService } from './hero.service';
providers: [
HeroService,
],
5,使用service
导入service:
// import { HEROES } from '../mock-heroes';
import { HeroService } from '../hero.service';
把 heroes 属性的定义改为一句简单的声明。后面会对它进行赋值。
// heroes = HEROES;
heroes: Hero[];
注入 HeroService
往构造函数中添加一个私有的 heroService,其类型为 HeroService。
constructor(
private heroService: HeroService
) { }
这个参数同时做了两件事:1. 声明了一个私有 heroService 属性,2. 把它标记为一个 HeroService 的注入点。
当 Angular 创建 HeroesComponent 时,依赖注入系统就会把这个 heroService 参数设置为 HeroService 的单例对象。
添加 getHeroes()用来获取数据
创建一个函数,以从服务中获取这些英雄数据。
getHeroes(): void {
this.heroes = this.heroService.getHeroes();
}
在 ngOnInit 中调用它
ngOnInit() {
this.getHeroes();
}
也可以在构造函数中调用 getHeroes(),但那不是最佳实践。
让构造函数保持简单,只做初始化操作,比如把构造函数的参数赋值给属性。 构造函数不应该做任何事。 它肯定不能调用某个函数来向远端服务(比如真实的数据服务)发起 HTTP 请求。
应该改为在 ngOnInit 生命周期钩子中调用 getHeroes(),并且等 Angular 构造出 HeroesComponent 的实例之后,找个恰当的时机调用 ngOnInit。
十一,Observable
import { Injectable } from '@angular/core';
@Injectable()
export class MessageService {
messages: string[] = [];
add(message: string) {
this.messages.push(message);
}
clear() {
this.messages = [];
}
constructor() { }
}
注入到 HeroService 中
/src/app/hero.service.ts
import { MessageService } from './message.service';
修改这个构造函数,添加一个私有的 messageService 属性参数。 Angular 将会在创建 HeroService 时把 MessageService 的单例注入到这个属性中。
constructor(
private messageService: MessageService
) { }
从 HeroService 中发送一条消息
修改 getHeroes 方法,在获取到英雄数组时发送一条消息。
getHeroes():Hero[]{
this.messageService.add('HeroService: fetched heroes');
return HEROES;
}
从 HeroService 中显示消息
导入 MessageService
/src/app/messages/messages.component.ts
import { MessageService } from '../message.service';
修改构造函数,添加一个 public 的 messageService 属性。 Angular 将会在创建 MessagesComponent 的实例时 把 MessageService 的实例注入到这个属性中。
constructor(
public messageService: MessageService
) { }
这个 messageService 属性必须是公共属性,因为你将会在模板中绑定到它。
绑定到 MessageService
<div *ngIf="messageService.messages.length">
<h2>Messages</h2>
<button class="clear"
(click)="messageService.clear()">clear</button>
<div *ngFor='let message of messageService.messages'> {{message}} </div>
</div>
这个模板直接绑定到了组件的 messageService 属性上。
*ngIf 只有当在有消息时才会显示消息区。
*ngFor 用来在一系列 <div> 元素中展示消息列表。
Angular 的事件绑定把按钮的 click 事件绑定到了 MessageService.clear()。
当你把 最终代码 某一页的内容添加到 messages.component.css 中时,这些消息会变得好看一些。
刷新浏览器,页面显示出了英雄列表。 滚动到底部,就会在消息区看到来自 HeroService 的消息。 点击“清空”按钮,消息区不见了。