目录
在开始之前,请确保您的计算机上有Node.js.
查看版本:ng version
一、新建web项目
输入项目名称
等待编译完成
编译完成
等同命令:ng new mosesAgl 然后用idea打开项目
二、启动项目
浏览界面
三、添加表格,css控制隔行变色
在app.component.html文件中添加表格
<table width='600' border='0' cellspacing='0' cellpadding='0' align='center'>
<tr>
<td>TSNAME</td>
<td>ALLSIZE</td>
<td>USEDSIZE</td>
<td>FREESIZE</td>
<td>SYL%</td>
</tr>
<tr>
<td>USERS</td>
<td>32767.98</td>
<td>4</td>
<td>32763.98</td>
<td>.01</td>
</tr>
<tr>
<td>UNDOTBS1</td>
<td>32767.98</td>
<td>13.56</td>
<td>32754.42</td>
<td>.04</td>
</tr>
<tr>
<td>REGISTRATION</td>
<td>120</td>
<td>.06</td>
<td>119.94</td>
<td>.05</td>
</tr>
<tr>
<td>TANG</td>
<td>70</td>
<td>.13</td>
<td>69.88</td>
<td>.18</td>
</tr>
<tr>
<td>EXAMPLE</td>
<td>32767.98</td>
<td>68.25</td>
<td>32699.73</td>
<td>.21</td>
</tr>
<tr>
<td>TBS</td>
<td>32767.98</td>
<td>.56</td>
<td>32767.42</td>
<td>0</td>
</tr>
</table>
在app.component.css文件中添加样式
body {
font-family: Arial;
font-size: 14px;
line-height: 180%;
padding-top: 20px;
}
/*第一行标题蓝色背景*/
table tr:first-child {
background: #0066CC;
color: #fff;
font-weight: bold;
}
table {
border-top: 1pt solid #C1DAD7;
border-left: 1pt solid #C1DAD7;
margin: 0 auto;
}
td {
padding: 5px 10px;
text-align: center;
border-right: 1pt solid #C1DAD7;
border-bottom: 1pt solid #C1DAD7;
}
/* odd 标识奇数行,even标识偶数行 */
tr:nth-of-type(odd) {
background: #c6f9f7
}
/*3的倍数行红色背景*/
tr:nth-child(3n+1) {
background: #FF0000;
}
/* 悬停鼠标变色 */
tr:hover {
background: #E0F0F0;
}
界面效果
四、创建组件
ng generate component heroes
添加一个hero属性HeroesComponent
heroes.component.ts
hero = 'Windstorm';
heroes.component.html
{{hero}}
显示HeroesComponent视图
app.component.html
<h1>{{title}}</h1>
<app-heroes></app-heroes>
创建一个Hero类
Hero
在文件src/app
夹中的自己的文件中创建一个类。给它id
和name
属性。
hero.ts
export class Hero {
id: number;
name: string;
}
将组件的hero
属性重构为类型Hero
。与初始化它id
的1
而得名Windstorm
。
heroes.component.ts
import {Component, OnInit} from '@angular/core';
import {Hero} from '../hero';
@Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
hero: Hero = {
id: 1,
name: 'Windstorm'
};
constructor() {
}
ngOnInit() {
}
}
更新模板中的绑定,名字id
并name
在详细信息布局中显示
heroes.component.html
<!--格式化-->
<h2>{{hero.name | uppercase}} Details</h2>
<div><span>id: </span>{{hero.id}}</div>
<div><span>name: </span>{{hero.name}}</div>
<!--双向绑定 需要导入FormsModule-->
<div>
<label>name:
<input [(ngModel)]="hero.name" placeholder="name">
</label>
</div>
导入FormsModule
app.module.ts
import {FormsModule} from '@angular/forms'; // <-- NgModel lives here
imports: [
BrowserModule,
FormsModule
],
请注意,AppModule
声明两个应用程序组件,AppComponent
和HeroesComponent
。
五、显示列表
创建模拟数据
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' }
];
导入
heroes.component.ts
import { HEROES } from '../mock-heroes';
heroes = HEROES;
用* ngFor 列出
heroes.component.html
<li *ngFor="let hero of heroes">
使用* ngIf 隐藏空白详细信息
<div *ngIf="selectedHero">
设置所选样式
添加[class.selected]
绑定到<li>
的HeroesComponent
模板
添加单击事件绑定
<li *ngFor="let hero of heroes" (click)="onSelect(hero)">
heroes.component.html完整代码
<h2>My Heroes</h2>
<ul class="heroes">
<!--添加[class.selected]绑定到<li>的HeroesComponent模板-->
<!--添加单击事件绑定-->
<li *ngFor="let hero of heroes"
[class.selected]="hero === selectedHero"
(click)="onSelect(hero)">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
<!--使用* ngIf 隐藏空白详细信息-->
<div *ngIf="selectedHero">
<!--格式化-->
<h2>{{selectedHero.name | uppercase}} Details</h2>
<div><span>id: </span>{{selectedHero.id}}</div>
<div>
<label>name:
<!--双向绑定 需要导入FormsModule-->
<input [(ngModel)]="selectedHero.name" placeholder="name">
</label>
</div>
</div>
添加单击事件处理程序
heroes.component.ts
selectedHero: Hero;
onSelect(hero: Hero): void {
this.selectedHero = hero;
}
六、主/明细组件
建立HeroDetailComponent
ng generate component hero-detail
从HeroesComponent
模板底部剪切详细信息的HTML ,并将其粘贴到模板中生成的样板上HeroDetailComponent
<!--使用* ngIf 隐藏空白详细信息-->
<div *ngIf="selectedHero">
<!--格式化-->
<h2>{{selectedHero.name | uppercase}} Details</h2>
<div><span>id: </span>{{selectedHero.id}}</div>
<div>
<label>name:
<!--双向绑定 需要导入FormsModule-->
<input [(ngModel)]="selectedHero.name" placeholder="name">
</label>
</div>
</div>
添加属性@Input()
HeroDetailComponent
类文件导入Hero
符号
hero-detail.component.ts
import { Hero } from '../hero';
修改@angular/core
import语句以包含该Input
符号
import { Component, OnInit, Input } from '@angular/core';
添加一个hero
属性,前面是装饰器。@Input()
@Input() hero: Hero;
外部绑定它
heroes.component.html
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
七、服务
创建HeroService
ng generate service hero
获取数据
hero.service.ts
导入Hero
和HEROES
import { Hero } from './hero';
import { HEROES } from './mock-heroes';
添加一个getHeroes
方法。
getHeroes(): Hero[] {
return HEROES;
}
更新HeroesComponent
删除HEROES
导入,导入HeroService
import { HeroService } from '../hero.service';
用heroes
简单的声明替换属性的定义
heroes: Hero[];
注入HeroService
constructor(private heroService: HeroService) { }
添加getHeroes()
getHeroes(): void { this.heroes = this.heroService.getHeroes(); }
调用ngOnInit
ngOnInit() { this.getHeroes(); }
可观察的数据
hero.service.ts
打开HeroService
文件并从RxJS 导入Observable
和of
符号
import { Observable, of } from 'rxjs';
替换getHeroes
方法
getHeroes(): Observable<Hero[]> { return of(HEROES); }
heroes.component.ts
getHeroes(): void { this.heroService.getHeroes() .subscribe(heroes => this.heroes = heroes); }
创建MessagesComponent
ng generate component messages
修改AppComponent
模板以显示生成的MessagesComponent
app.component.html
<app-messages></app-messages>
创建MessageService
ng generate service message
替换message.service.ts内容
import {Injectable} from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class MessageService {
messages: string[] = [];
add(message: string) {
this.messages.push(message);
}
clear() {
this.messages = [];
}
}
HeroService
导入MessageService
。
import { MessageService } from './message.service';
constructor(private messageService: MessageService) { }
修改getHeroes
方法以在获取英雄时发送消息
getHeroes(): Observable<Hero[]> {
// TODO: send the message _after_ fetching the heroes
this.messageService.add('HeroService: fetched heroes');
return of(HEROES);
}
MessagesComponent
导入MessageService
import { MessageService } from '../message.service';
constructor(public messageService: MessageService) {}
使用MessagesComponent
以下内容替换CLI生成的模板
<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>
八、路由
添加AppRoutingModule
ng generate module app-routing --flat --module=app
--flat
放入文件src/app
而不是自己的文件夹。--module=app
告诉CLI将其注册到imports
数组中AppModule
。
添加路线
import { HeroesComponent } from './heroes/heroes.component';
const routes: Routes = [
{ path: 'heroes', component: HeroesComponent }
];
path
:与浏览器地址栏中的URL匹配的字符串。component
:导航到此路由时路由器应创建的组件。
RouterModule.forRoot()
imports: [ RouterModule.forRoot(routes) ],
添加RouterOutlet
AppComponent模板用<router-outlet>元素替换<app-heroes>元素。
<router-outlet></router-outlet>
添加导航链接
<nav> <a routerLink="/heroes">Heroes</a> </nav>
app.component.html
<h1>{{title}}</h1>
<nav>
<a routerLink="/dashboard">Dashboard</a>
<a routerLink="/heroes">Heroes</a>
</nav>
<router-outlet></router-outlet>
<app-messages></app-messages>
css控制隔行变色table及其样式移动到了hero-detail
app.component.css
h1 {
font-size: 1.2em;
color: #999;
margin-bottom: 0;
}
h2 {
font-size: 2em;
margin-top: 0;
padding-top: 0;
}
nav a {
padding: 5px 10px;
text-decoration: none;
margin-top: 10px;
display: inline-block;
background-color: #eee;
border-radius: 4px;
}
nav a:visited, a:link {
color: #607d8b;
}
nav a:hover {
color: #039be5;
background-color: #cfd8dc;
}
nav a.active {
color: #039be5;
}
添加仪表板视图
ng generate component dashboard
每次添加组件以后app.module.ts有可能名称不一致报错,需要手动修改
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms'; // <-- NgModel lives here
import {AppComponent} from './app.component';
import {HeroesComponent} from './heroes/heroes.component';
import {HeroDetailComponent} from './hero-detail/hero-detail.component';
import {MessagesComponent} from './messages/messages.component';
import {AppRoutingModule} from './/app-routing.module';
import {DashboardComponent} from './dashboard/dashboard.component';
@NgModule({
// 声明HeroesComponent
declarations: [
AppComponent,
HeroesComponent,
HeroDetailComponent,
MessagesComponent,
DashboardComponent
],
imports: [
BrowserModule,
FormsModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
title = '王者归来';
}
dashboard.component.html
<h3>Top Heroes</h3>
<div class="grid grid-pad">
<a *ngFor="let hero of heroes" class="col-1-4">
<div class="module hero">
<h4>{{hero.name}}</h4>
</div>
</a>
</div>
dashboard.component.ts
import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';
import { HeroService } from '../hero.service';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: [ './dashboard.component.css' ]
})
export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
constructor(private heroService: HeroService) { }
ngOnInit() {
this.getHeroes();
}
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes.slice(1, 5));
}
}
dashboard.component.css
/* DashboardComponent's private CSS styles */
[class*='col-'] {
float: left;
padding-right: 20px;
padding-bottom: 20px;
}
[class*='col-']:last-of-type {
padding-right: 0;
}
a {
text-decoration: none;
}
*, *:after, *:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
h3 {
text-align: center;
margin-bottom: 0;
}
h4 {
position: relative;
}
.grid {
margin: 0;
}
.col-1-4 {
width: 25%;
}
.module {
padding: 20px;
text-align: center;
color: #eee;
max-height: 120px;
min-width: 120px;
background-color: #607d8b;
border-radius: 2px;
}
.module:hover {
background-color: #eee;
cursor: pointer;
color: #607d8b;
}
.grid-pad {
padding: 10px 0;
}
.grid-pad > [class*='col-']:last-of-type {
padding-right: 20px;
}
@media (max-width: 600px) {
.module {
font-size: 10px;
max-height: 75px; }
}
@media (max-width: 1024px) {
.grid {
margin: 0;
}
.module {
min-width: 60px;
}
}
添加仪表板路由
import { DashboardComponent } from './dashboard/dashboard.component';
{ path: 'dashboard', component: DashboardComponent },
添加默认路由
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
添加仪表板链接到shell
<a routerLink="/dashboard">Dashboard</a>
将徽章和名称包裹在一个锚元素()中,并向锚点添加一个与仪表板模板中相同的属性*ngFor
<a>
routerLink
heroes.component.html
<li *ngFor="let hero of heroes">
<a routerLink="/detail/{{hero.id}}">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</a>
</li>
修复私有样式表(heroes.component.css
)以使列表看起来像以前一样
/* HeroesComponent's private CSS styles */
.heroes {
margin: 0 0 2em 0;
list-style-type: none;
padding: 0;
width: 15em;
}
.heroes li {
position: relative;
cursor: pointer;
background-color: #EEE;
margin: .5em;
padding: .3em 0;
height: 1.6em;
border-radius: 4px;
}
.heroes li:hover {
color: #607D8B;
background-color: #DDD;
left: .1em;
}
.heroes a {
color: #888;
text-decoration: none;
position: relative;
display: block;
width: 250px;
}
.heroes a:hover {
color:#607D8B;
}
.heroes .badge {
display: inline-block;
font-size: small;
color: white;
padding: 0.8em 0.7em 0 0.7em;
background-color: #607D8B;
line-height: 1em;
position: relative;
left: -1px;
top: -4px;
height: 1.8em;
min-width: 16px;
text-align: right;
margin-right: .8em;
border-radius: 4px 0 0 4px;
}
HeroesComponent不再使用该onSelect()
方法和selectedHero
属性
import {Component, OnInit} from '@angular/core';
import {HeroService} from '../hero.service';
import {Hero} from '../hero';
@Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
heroes: Hero[];
constructor(private heroService: HeroService) {
}
ngOnInit() {
this.getHeroes();
}
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes);
}
}
将HeroDetailComponent
需要一种新的方式来获得英雄到显示器。
- 获取创建它的路线,
id
从路线中提取id
通过服务器从服务器获取英雄HeroService
将ActivatedRoute
,HeroService
和Location
服务注入构造函数,将其值保存在私有字段中:
hero-detail.component.ts
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {Location} from '@angular/common';
import {Hero} from '../hero';
import {HeroService} from '../hero.service';
@Component({
selector: 'app-hero-detail',
templateUrl: './hero-detail.component.html',
styleUrls: ['./hero-detail.component.css']
})
export class HeroDetailComponent implements OnInit {
hero: Hero;
constructor(
private route: ActivatedRoute,
private heroService: HeroService,
private location: Location
) {
}
ngOnInit(): void {
this.getHero();
}
getHero(): void {
const id = +this.route.snapshot.paramMap.get('id');
this.heroService.getHero(id)
.subscribe(hero => this.hero = hero);
}
goBack(): void {
this.location.back();
}
}
HeroService
添加getHero()
方法
getHero(id: number): Observable<Hero> {
// TODO: send the message _after_ fetching the hero
this.messageService.add(`HeroService: fetched hero id=${id}`);
return of(HEROES.find(hero => hero.id === id));
}
HeroDetail添加返回按钮,绑定到组件的goBack()
方法
<button (click)="goBack()">go back</button>
dashboard.component.html
<h3>Top Heroes</h3>
<div class="grid grid-pad">
<a *ngFor="let hero of heroes" class="col-1-4"
routerLink="/detail/{{hero.id}}">
<div class="module hero">
<h4>{{hero.name}}</h4>
</div>
</a>
</div>
九、http
启用HTTP服务
从npm安装内存中的Web API包
npm install angular-in-memory-web-api --save
生成src/app/in-memory-data.service.ts
ng generate service InMemoryData
import {InMemoryDbService} from 'angular-in-memory-web-api';
import {Hero} from './hero';
import {Injectable} from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class InMemoryDataService implements InMemoryDbService {
createDb() {
const heroes = [
{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'}
];
return {heroes};
}
// Overrides the genId method to ensure that a hero always has an id.
// If the heroes array is empty,
// the method below returns the initial number (11).
// if the heroes array is not empty, the method below returns the highest
// hero id + 1.
genId(heroes: Hero[]): number {
return heroes.length > 0 ? Math.max(...heroes.map(hero => hero.id)) + 1 : 11;
}
}
创建HeroSearchComponent
ng generate component hero-search
app.module.ts
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {FormsModule} from '@angular/forms';
// 导入符号@angular/common/http
import {HttpClientModule} from '@angular/common/http';
// 导入HttpClientInMemoryWebApiModule的InMemoryDataService类
import {HttpClientInMemoryWebApiModule} from 'angular-in-memory-web-api';
import {InMemoryDataService} from './in-memory-data.service';
import {AppRoutingModule} from './app-routing.module';
import {AppComponent} from './app.component';
import {DashboardComponent} from './dashboard/dashboard.component';
import {HeroDetailComponent} from './hero-detail/hero-detail.component';
import {HeroesComponent} from './heroes/heroes.component';
import {HeroSearchComponent} from './hero-search/hero-search.component';
import {MessagesComponent} from './messages/messages.component';
@NgModule({
imports: [
BrowserModule,
FormsModule,
AppRoutingModule,
HttpClientModule,
// 添加HttpClientInMemoryWebApiModule到数组 中
// The HttpClientInMemoryWebApiModule module intercepts HTTP requests
// and returns simulated server responses.
// Remove it when a real server is ready to receive requests.
HttpClientInMemoryWebApiModule.forRoot(
InMemoryDataService, {dataEncapsulation: false}
)
],
declarations: [
AppComponent,
DashboardComponent,
HeroesComponent,
HeroDetailComponent,
MessagesComponent,
HeroSearchComponent
],
bootstrap: [AppComponent]
})
export class AppModule {
}
hero.service.ts
import {Injectable} from '@angular/core';
// 导入HTTP符号
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {Observable, of} from 'rxjs';
// 导入catchError符号rxjs/operators
import {catchError, map, tap} from 'rxjs/operators';
import {Hero} from './hero';
import {MessageService} from './message.service';
const httpOptions = {
headers: new HttpHeaders({'Content-Type': 'application/json'})
};
@Injectable({providedIn: 'root'})
export class HeroService {
// 资源的地址定义heroesUrl表单:base/:collectionName
private heroesUrl = 'api/heroes'; // URL to web api
// 私有属性中注入构造函数http
constructor(
private http: HttpClient,
private messageService: MessageService) {
}
// 通过HttpClient 获取,.pipe()方法扩展可观察结果并给它一个catchError()运算符
/** GET heroes from the server */
getHeroes(): Observable<Hero[]> {
return this.http.get<Hero[]>(this.heroesUrl)
.pipe(
tap(_ => this.log('fetched heroes')),
catchError(this.handleError('getHeroes', []))
);
}
/** GET hero by id. Return `undefined` when id not found */
getHeroNo404<Data>(id: number): Observable<Hero> {
const url = `${this.heroesUrl}/?id=${id}`;
return this.http.get<Hero[]>(url)
.pipe(
map(heroes => heroes[0]), // returns a {0|1} element array
tap(h => {
const outcome = h ? `fetched` : `did not find`;
this.log(`${outcome} hero id=${id}`);
}),
catchError(this.handleError<Hero>(`getHero id=${id}`))
);
}
/** GET hero by id. Will 404 if id not found */
getHero(id: number): Observable<Hero> {
const url = `${this.heroesUrl}/${id}`;
return this.http.get<Hero>(url).pipe(
tap(_ => this.log(`fetched hero id=${id}`)),
catchError(this.handleError<Hero>(`getHero id=${id}`))
);
}
/* GET heroes whose name contains search term */
searchHeroes(term: string): Observable<Hero[]> {
if (!term.trim()) {
// if not search term, return empty hero array.
return of([]);
}
return this.http.get<Hero[]>(`${this.heroesUrl}/?name=${term}`).pipe(
tap(_ => this.log(`found heroes matching "${term}"`)),
catchError(this.handleError<Hero[]>('searchHeroes', []))
);
}
Save methods //
/** POST: add a new hero to the server */
addHero(hero: Hero): Observable<Hero> {
return this.http.post<Hero>(this.heroesUrl, hero, httpOptions).pipe(
tap((hero: Hero) => this.log(`added hero w/ id=${hero.id}`)),
catchError(this.handleError<Hero>('addHero'))
);
}
/** DELETE: delete the hero from the server */
deleteHero(hero: Hero | number): Observable<Hero> {
const id = typeof hero === 'number' ? hero : hero.id;
const url = `${this.heroesUrl}/${id}`;
return this.http.delete<Hero>(url, httpOptions).pipe(
tap(_ => this.log(`deleted hero id=${id}`)),
catchError(this.handleError<Hero>('deleteHero'))
);
}
/** PUT: update the hero on the server */
updateHero(hero: Hero): Observable<any> {
return this.http.put(this.heroesUrl, hero, httpOptions).pipe(
tap(_ => this.log(`updated hero id=${hero.id}`)),
catchError(this.handleError<any>('updateHero'))
);
}
/**
* Handle Http operation that failed.
* Let the app continue.
* @param operation - name of the operation that failed
* @param result - optional value to return as the observable result
*/
private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
// TODO: send the error to remote logging infrastructure
console.error(error); // log to console instead
// TODO: better job of transforming error for user consumption
this.log(`${operation} failed: ${error.message}`);
// Let the app keep running by returning an empty result.
return of(result as T);
};
}
// 注射MessageService。将它包装在一个私有log()方法中
/** Log a HeroService message with the MessageService */
private log(message: string) {
this.messageService.add(`HeroService: ${message}`);
}
}
更新
hero-detail.component.ts
save(): void {
this.heroService.updateHero(this.hero)
.subscribe(() => this.goBack());
}
hero-detail.component.html
<button (click)="save()">save</button>
添加和删除
heroes.component.ts
import {Component, OnInit} from '@angular/core';
import {Hero} from '../hero';
import {HeroService} from '../hero.service';
@Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
heroes: Hero[];
constructor(private heroService: HeroService) {
}
ngOnInit() {
this.getHeroes();
}
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes);
}
add(name: string): void {
name = name.trim();
if (!name) {
return;
}
this.heroService.addHero({name} as Hero)
.subscribe(hero => {
this.heroes.push(hero);
});
}
delete(hero: Hero): void {
this.heroes = this.heroes.filter(h => h !== hero);
this.heroService.deleteHero(hero).subscribe();
}
}
heroes.component.html
<h2>My Heroes</h2>
<div>
<label>Hero name:
<input #heroName/>
</label>
<!-- (click) passes input value to add() and then clears the input -->
<button (click)="add(heroName.value); heroName.value=''">
add
</button>
</div>
<ul class="heroes">
<!--<!–添加[class.selected]绑定 添加单击事件绑定–>-->
<!--<li *ngFor="let hero of heroes" [class.selected]="hero === selectedHero" (click)="onSelect(hero)">-->
<li *ngFor="let hero of heroes">
<a routerLink="/detail/{{hero.id}}">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</a>
<button class="delete" title="delete hero"
(click)="delete(hero)">x
</button>
</li>
</ul>
heroes.component.css
/* HeroesComponent's private CSS styles */
.heroes {
margin: 0 0 2em 0;
list-style-type: none;
padding: 0;
width: 15em;
}
.heroes li {
position: relative;
cursor: pointer;
background-color: #EEE;
margin: .5em;
padding: .3em 0;
height: 1.6em;
border-radius: 4px;
}
.heroes li:hover {
color: #607D8B;
background-color: #DDD;
left: .1em;
}
.heroes a {
color: #888;
text-decoration: none;
position: relative;
display: block;
width: 250px;
}
.heroes a:hover {
color:#607D8B;
}
.heroes .badge {
display: inline-block;
font-size: small;
color: white;
padding: 0.8em 0.7em 0 0.7em;
background-color: #607D8B;
line-height: 1em;
position: relative;
left: -1px;
top: -4px;
height: 1.8em;
min-width: 16px;
text-align: right;
margin-right: .8em;
border-radius: 4px 0 0 4px;
}
button {
background-color: #eee;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
cursor: hand;
font-family: Arial;
}
button:hover {
background-color: #cfd8dc;
}
button.delete {
position: relative;
left: 194px;
top: -32px;
background-color: gray !important;
color: white;
}
按名称搜索
dashboard.component.html
<app-hero-search></app-hero-search>
创建HeroSearchComponent
ng generate component hero-search
hero-search.component.html
<div id="search-component">
<h4>Hero Search</h4>
<!--search()通过绑定到文本框input事件的事件来调用该方法。-->
<input #searchBox id="search-box" (input)="search(searchBox.value)"/>
<ul class="search-result">
<!--这$是一个表示heroes$是Observable,而不是数组的约定。-->
<!--标识了Angular的。*ngForObservable|asyncAsyncPipe-->
<li *ngFor="let hero of heroes$ | async">
<a routerLink="/detail/{{hero.id}}">
{{hero.name}}
</a>
</li>
</ul>
</div>
hero-search.component.ts
import {Component, OnInit} from '@angular/core';
import {Observable, Subject} from 'rxjs';
import {
debounceTime, distinctUntilChanged, switchMap
} from 'rxjs/operators';
import {Hero} from '../hero';
import {HeroService} from '../hero.service';
@Component({
selector: 'app-hero-search',
templateUrl: './hero-search.component.html',
styleUrls: ['./hero-search.component.css']
})
export class HeroSearchComponent implements OnInit {
// 注意声明heroes$为Observable
heroes$: Observable<Hero[]>;
// 该searchTerms属性被声明为RxJS Subject。
private searchTerms = new Subject<string>();
constructor(private heroService: HeroService) {
}
// Push a search term into the observable stream.
search(term: string): void {
this.searchTerms.next(term);
}
ngOnInit(): void {
this.heroes$ = this.searchTerms.pipe(
// 等待直到新字符串事件的流程在传递最新字符串之前暂停300毫秒
// wait 300ms after each keystroke before considering the term
debounceTime(300),
// 确保仅在过滤器文本更改时才发送请求
// ignore new term if same as previous term
distinctUntilChanged(),
// 它取消并丢弃先前的搜索可观察量,仅返回可观察的最新搜索服务。
// switch to new search observable each time the term changes
switchMap((term: string) => this.heroService.searchHeroes(term)),
);
}
}
hero-search.component.css
/* HeroSearch private styles */
.search-result li {
border-bottom: 1px solid gray;
border-left: 1px solid gray;
border-right: 1px solid gray;
width: 195px;
height: 16px;
padding: 5px;
background-color: white;
cursor: pointer;
list-style-type: none;
}
.search-result li:hover {
background-color: #607D8B;
}
.search-result li a {
color: #888;
display: block;
text-decoration: none;
}
.search-result li a:hover {
color: white;
}
.search-result li a:active {
color: white;
}
#search-box {
width: 200px;
height: 20px;
}
ul.search-result {
margin-top: 0;
padding-left: 0;
}
十、集成bootstrap和jasper报表
安装bootstrap
npm i bootstrap -s
导入bootstrap样式
将目录下的 ../node_modules/bootstrap/dist/css/bootstrap.min.css 添加到项目的angular.json文件的styles中
创建报表组件
ng generate component report
report.component.ts
import {Component, OnInit} from '@angular/core';
import {ReportService} from "../services/report.service";
import {DomSanitizer} from "@angular/platform-browser";
@Component({
selector: 'app-report',
templateUrl: './report.component.html',
styleUrls: ['./report.component.css']
})
export class ReportComponent implements OnInit {
reportSrc: string;
imgsrc = 'https://c.staticblitz.com/assets/client/components/SideMenu/blitz_logo-11cebad97cad4b50bc955cf72f532d1b.png';
constructor(public reportService: ReportService, public sanitizer: DomSanitizer) {
}
ngOnInit() {
this.reportChange("crosstab");
}
fileChange(e): void {
const file = e.srcElement.files[0]; // 获取图片这里只操作一张图片
this.imgsrc = window.URL.createObjectURL(file); // 获取上传的图片临时路径
}
reportChange(name: string): void {
this.reportSrc = 'http://localhost:8889/' + name + '?whereSql=cost%3C15&inline=true';
}
}
report.component.html
<div class="container">
<h2>报表实例</h2>
<div class="container-fluid">
<nav class="breadcrumb">
<button class="clear"
(click)="reportChange('product')">product
</button>
<button class="clear"
(click)="reportChange('crosstab')">crosstab
</button>
</nav>
<div class="row">
<div class="col-md-3 bg-success">
<p>上传图片显示缩略图</p>
<img height="100px" width="100px" [src]="sanitizer.bypassSecurityTrustUrl(imgsrc)">
<input type="file" (change)="fileChange($event)">
</div>
<div class="col-md-9 bg-warning">
<iframe [src]="sanitizer.bypassSecurityTrustResourceUrl(reportSrc)" class="report"></iframe>
</div>
</div>
</div>
</div>
展示效果