1.做的东西
本次我做的是英雄之旅应用的开发,简单实现了其增删改查功能并设计了一点简单的样式。
2.开发过程
- 创建一个名为angular-tour-of-heroes的angular项目。
- 在自动生成的app组件中添加一些html内容。
- 创建英雄类和英雄组件,英雄类用于存放英雄信息,为英雄组件添加一些事件比如点击显示英雄信息(需要添加一个onselect方法),再为其设置一点css样式。
- 创建英雄详细信息的组件,把原本写在英雄组件里的英雄详细信息逻辑委派到该组件。
- 创建HeroService服务,用来获取英雄数据。
- 创建一个message组件,用来显示消息。把messageService注入到HeroService中,HeroService被注入到HeroesComponent中。把messageService的属性改成公共属性,然后拿去绑定模板。
- 添加approuting模组。
- 添加路由出口RouterOutlet。
- 添加路由链接RouterLink。
- 添加仪表盘视图。
- 添加仪表盘路由。
- 添加默认路由。
- 把仪表盘链接添加到壳组件中。
- 设计导航到英雄详情,先从英雄组件里删除英雄详情,再添加英雄详情视图,再用仪表盘组件链接英雄。
- 设计从服务器端获取数据,先启用HTTP服务,然后模拟数据服务器。
- 设计通过HTTPClient获取英雄,其中应通过id获取英雄。
- 设计修改英雄的方法和删除英雄的方法。
- 设计根据名字搜索的方法
- 把该项目部署到Github上
- 以下是部分方法的实现代码:
英雄类(包含有点击显示英雄详细信息的功能,添加,删除等功能):
@Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
selectedHero?: Hero;
heroes: Hero[] = [];
constructor(private heroService: HeroService, private messageService: MessageService) { }
ngOnInit(): void {
this.getHeroes();
}
onSelect(hero: Hero): void {
this.selectedHero = hero;
this.messageService.add(`HeroesComponent: Selected hero id=${hero.id}`);
}
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.id).subscribe();
}
}
英雄详细信息类(包含输入功能,获取英雄,返回上一个页面,保存功能):
@Component({
selector: 'app-hero-detail',
templateUrl: './hero-detail.component.html',
styleUrls: ['./hero-detail.component.css']
})
export class HeroDetailComponent implements OnInit {
constructor(
private route: ActivatedRoute,
private heroService: HeroService,
private location: Location
) {}
@Input() hero?: Hero;
ngOnInit(): void {
this.getHero();
}
getHero(): void {
const id = Number(this.route.snapshot.paramMap.get('id'));
this.heroService.getHero(id)
.subscribe(hero => this.hero = hero);
}
goBack(): void {
this.location.back();
}
save(): void {
if (this.hero) {
this.heroService.updateHero(this.hero)
.subscribe(() => this.goBack());
}
}
}
仪表盘类():
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: [ './dashboard.component.css' ]
})
export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
constructor(private heroService: HeroService) { }
ngOnInit(): void {
this.getHeroes();
}
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes.slice(1, 5));
}
}
英雄查找方法类():
@Component({
selector: 'app-hero-search',
templateUrl: './hero-search.component.html',
styleUrls: [ './hero-search.component.css' ]
})
export class HeroSearchComponent implements OnInit {
heroes$!: Observable<Hero[]>;
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(
// 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)),
);
}
}
信息类(用来输出选择的东西的相关信息):
@Component({
selector: 'app-messages',
templateUrl: './messages.component.html',
styleUrls: ['./messages.component.css']
})
export class MessagesComponent implements OnInit {
constructor(public messageService: MessageService) {}
ngOnInit(): void {
}
}
<div *ngIf="messageService.messages.length">
<h2>Messages</h2>
<button type="button" class="clear"
(click)="messageService.clear()">Clear messages</button>
<div *ngFor='let message of messageService.messages'> {{message}} </div>
</div>
@Injectable({
providedIn: 'root',
})
export class MessageService {
messages: string[] = [];
add(message: string) {
this.messages.push(message);
}
clear() {
this.messages = [];
}
}
模拟数据库类(因为本项目并没有真正连接到数据库,所以用来模拟):
@Injectable({
providedIn: 'root',
})
export class InMemoryDataService implements InMemoryDbService {
createDb() {
const heroes = [
{ id: 12, name: '山丘之王' },
{ id: 13, name: '血魔法师' },
{ id: 14, name: '影魔' },
{ id: 15, name: '暗夜猎手' },
{ id: 16, name: '月之女祭司' },
{ id: 17, name: '矮人火枪手' },
{ id: 18, name: '恶魔猎手' },
{ id: 19, name: '卡尔' },
{ id: 20, name: '驯兽师' }
];
return {heroes};
}
genId(heroes: Hero[]): number {
return heroes.length > 0 ? Math.max(...heroes.map(hero => hero.id)) + 1 : 11;
}
}
3.遇到的问题及解决方式和结果
- 在修改英雄组件的属性时一直报错,根据报错信息找半天也没找到,后面一行一行对比了Angular教程里的代码解决了,发现是有不需要更改的被改掉了。
- 检测不到Git,后面重新下载了最新版git解决了该问题。
- 在部署时报了这种错误后来换了如下方式,成功了,但仍然不明白是什么原因。
4.部署网页到Github时只成功过一次,尝试了很多次,错误原因多种多样,该问题还尚未解决。
4.总结
这次课程任务我选择的是使用前端框架Angular进行英雄之旅的开发,实现了CRUD
即增删查改的功能并具有一定的样式。实践的结果虽然比较一般,样式也不够好看,但总算是完成了最基本的一些操作。通过英雄之旅的学习,我对Angular开发有了一定的了解,同时也让我也意识到想要用好Angular很难。经过一个学期的学习,我现在基本可以运用Html,Css,JS去实现一些网页的制作,算是有了更进一步学习的基础。