前面已经说到了基本的集成可开发准备工作,Angular 开发(一)。接下来开始逻辑部分的编写
段子列表获取,路由跳转详情
新建段子列表的组件:
ng g c newList
命令的方式会自动在app.module.ts
中导入相关组件,declarations中自动声明 NewListComponent
app-routing.module.ts
中增加列表路由,并设置重定向到列表页。并在根组件app.component.htm
l中增加,这样后面的路由页面都会渲染在此!
<div class="root-container">
<router-outlet></router-outlet>
</div>
app-routing.module.ts
主要代码:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { NewListComponent } from "./new-list/new-list.component";
const routes: Routes = [{
path: "",
redirectTo: "newList",
pathMatch: "full"
}, {
path: "newList",
component: NewListComponent
}]
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
新建获取列表和详情的service:
ng g s newList
业务代码:
newlist.service.ts
获取段子列表::
接口:
https://api.apiopen.top/getJoke
type string 否 指定查询类型,可选参数(all/video/image/gif/text) all
page string 否 页码(传0或者不传会随机推荐) 1 count string 否 每页返回数量 10
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from "@angular/common/http";
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class NewlistService {
constructor(private http: HttpClient) { }
//获取列表
getList(type: string, page: number):Observable<any> {
const params = new HttpParams().set("type", type).set("page", String(page));
return this.http.request('get',"/getJoke",{
params
})
}
//获取详情
getDetail(id:string){
const params = new HttpParams().set("sid", id);
return this.http.request('get',"/getSingleJoke",{
params
})
}
}
这里我使用了http的request,而没有使用其他的get去请求。其他的方法可以自行去Angular官网查看
new-list.component.ts
中设置5种type集合以及获取每种type下的数据。
import { Component, OnInit } from '@angular/core';
import { Router } from "@angular/router";
import { NewlistService } from './newlist.service';
@Component({
selector: 'app-new-list',
templateUrl: './new-list.component.html',
styleUrls: ['./new-list.component.scss']
})
export class NewListComponent implements OnInit {
TypeList = [{
key: "all",
text: "全部"
}, {
key: "text",
text: "文字"
}, {
key: "video",
text: "视频"
}, {
key: "image",
text: "图片"
}, {
key: "gif",
text: "动态图"
}
];
listType = "text";
page: number = 1;
DataList: any[] = [];
initLoading = true;
loadingMore = false;
list: Array<{ loading: boolean; name: any }> = [];
constructor(private newlist: NewlistService, private router: Router) { }
ngOnInit() {
this.getList();
}
nzSelectChange(select: any) {
this.DataList = [];
this.listType = this.TypeList[select.index].key;
this.page = 1;
this.getList();
}
getList() {
this.initLoading = true;
this.newlist.getList(this.listType, this.page).subscribe(res => {
this.DataList = this.DataList.concat(res);
this.initLoading = false
})
}
/**
* 下一页
*/
onLoadMore() {
this.page++;
this.getList()
}
details(id) {
//详情页
this.router.navigate(['detail'], {
queryParams: {
sid: id
}
})
}
goMusic() {
//前往music页面:
this.router.navigate(['musiclist'])
}
}
new-list.component.html 使用ng-zorro绘制页面
<div>
<nz-tabset (nzSelectChange)="nzSelectChange($event)">
<nz-tab [nzTitle]="item.text" *ngFor="let item of TypeList">
<ng-template nz-tab>
<nz-list [nzDataSource]="DataList" [nzItemLayout]="'horizontal'" [nzLoading]="initLoading" [nzRenderItem]="item"
[nzLoadMore]="loadMore">
<ng-template #item let-items>
<nz-list-item (click)="details(items.sid)" class="list-item-center">
<nz-skeleton [nzAvatar]="true" [nzActive]="true" [nzTitle]="false" [nzLoading]="initLoading">
<nz-card style="width: 300px" nzHoverable [nzCover]="coverTemplate">
<nz-card-meta [nzTitle]="titleTemplate" [nzDescription]="items.text" [nzAvatar]="avatarTemplate">
</nz-card-meta>
</nz-card>
<ng-template #avatarTemplate>
<nz-avatar nzIcon="user" [nzSrc]="items.header"></nz-avatar>
</ng-template>
<ng-template #titleTemplate>
<span>{{items.name}}</span> <span>{{items.passtime}}</span>
</ng-template>
<ng-template #coverTemplate>
<img *ngIf="items.type=='image'||items.type=='gif'" [src]="items.images" />
<img *ngIf="items.type=='video'" [src]="items.thumbnail" />
</ng-template>
</nz-skeleton>
</nz-list-item>
</ng-template>
<ng-template #loadMore>
<div class="loadmore">
<button nz-button *ngIf="!loadingMore" (click)="onLoadMore()">阅读更多</button>
</div>
</ng-template>
</nz-list>
</ng-template>
</nz-tab>
<nz-tab [nzTitle]="musicTemplate">
<ng-template #musicTemplate>
<span (click)="goMusic()"><i nz-icon nzType="play-circle" nzTheme="outline"></i>音乐台</span>
</ng-template>
</nz-tab>
</nz-tabset>
</div>
运行如下:
获取段子详情
新建详情组件
ng g c detail
app-routing.module.ts中增加detail路由
import { DetailComponent } from "./detail/detail.component";
省略...
{
path: "detail",
component: DetailComponent
}
省略...
列表跳转到详情(detail):列表new-list.component.ts
中主要代码
import { Router } from "@angular/router";
constructor(private newlist: NewlistService, private router: Router) { }
details(id) {
//详情页
this.router.navigate(['detail'], {
queryParams: {
sid: id
}
})
}
可以看到通过queryParams来进行参数传递。学过vue的同学可以类比于router,push 跳转中的params参数。
而详情中通过ActivatedRoute
去获取传递过来的参数,如下constructor函数中的实现就是获取sid,当然这里也可以通过snapshot来获取参数,具体用法这里不做赘述
detail.component.ts
获取详情代码
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from "@angular/router";
import { NewlistService } from '../new-list/newlist.service';
import { BaseClass } from '../base-class';
@Component({
selector: 'app-detail',
templateUrl: './detail.component.html',
styleUrls: ['./detail.component.scss']
})
export class DetailComponent extends BaseClass implements OnInit {
Id = ""
detailData = null
constructor(private activeRouter: ActivatedRoute, private newListService: NewlistService) {
super();
activeRouter.queryParams.subscribe(queryParams => {
this.Id = queryParams.sid;
})
}
ngOnInit() {
this.getDetails();
}
getDetails() {
this.newListService.getDetail(this.Id).subscribe(res => {
this.detailData = res;
console.log(this.detailData.type)
})
}
}
detail.component.html
部分
<div class="container">
<nz-card [nzTitle]="nzTitle">
<div *ngIf="detailData.type=='video'">
<video [src]="detailData.video"></video>
</div>
<div *ngIf="detailData.type=='image'||detailData.type=='gif'">
<img [src]="detailData.images" alt="">
</div>
<div style="margin-top: 10px;margin-bottom: 10px">
<span>{{detailData.text}}</span>
</div>
<nz-card-meta [nzTitle]="detailData.top_comments_name" [nzDescription]="detailData.top_comments_content"
[nzAvatar]="avatarTemplate">
</nz-card-meta>
</nz-card>
<ng-template #avatarTemplate>
<nz-avatar [nzSrc]="detailData.top_comments_header"></nz-avatar>
</ng-template>
<ng-template #nzTitle>
<span (click)="back()"><i nz-icon [nzType]="'left'"></i>返回</span>
</ng-template>
</div>
渲染详情结果:
音乐列表搜
创建音乐列表的组件
ng g c musiclist
并增加路由:
import { MusiclistComponent } from "./musiclist/musiclist.component"
省略...
{
path: "musiclist",
component: MusiclistComponent
}
省略...
创建music搜索的service
ng g s music
增加搜索音乐请求方法
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class MusicService {
constructor(private http: HttpClient) { }
searchMusic(name: string): Observable<any> {
const params = new HttpParams().set("name", name);
return this.http.request("get", "/searchMusic", {
params
})
}
}
musiclist.component.ts
引入musiclist service
进行数据请求
musiclist.component.ts
:
import { Component, OnInit } from '@angular/core';
import { MusicService } from "./music.service"
import { Router } from '@angular/router';
import { BaseClass } from '../base-class';
@Component({
selector: 'app-musiclist',
templateUrl: './musiclist.component.html',
styleUrls: ['./musiclist.component.scss']
})
export class MusiclistComponent extends BaseClass implements OnInit {
MusicList = [];
name = "";
loading = false;
constructor(private musicService: MusicService, private router: Router) {
super();
}
ngOnInit() {
}
searchMusic() {
this.loading = true;
this.musicService.searchMusic(this.name).subscribe(res => {
if (res != "") {
this.MusicList = res;
} else {
this.MusicList = [];
}
this.loading = false;
})
}
playMusic(index: any) {
console.log(index);
let list = [];
this.MusicList.forEach(item => {
list.push({
name: item.title,
artist: item.author,
url: item.url,
cover: item.pic,
theme: '#ebd0c2'
})
})
sessionStorage.setItem("musicList", JSON.stringify(list));
this.router.navigate(['music'],{
queryParams:{
index:index
}
})
}
}
musiclist.component.html
歌曲搜索列表页面:
<div class="music-list-container">
<nz-input-group nzSearch [nzAddOnAfter]="suffixIconButton">
<input type="text" [(ngModel)]="name" nz-input placeholder="请输入歌曲关键词" />
</nz-input-group>
<ng-template #suffixIconButton>
<button (click)="searchMusic()" nz-button nzType="primary" nzSearch><i nz-icon type="search"></i></button>
</ng-template>
<nz-list [nzDataSource]="MusicList" [nzRenderItem]="item" [nzItemLayout]="'horizontal'" [nzLoading]="loading">
<ng-template #item let-item let-index="index">
<nz-list-item (click)="playMusic(index)">
<nz-card style="width:350px" [nzCover]="coverTemplate">
<nz-card-meta [nzTitle]="item.author" [nzAvatar]="avatarTemplate" [nzDescription]="item.title">
</nz-card-meta>
</nz-card>
<ng-template #avatarTemplate>
<nz-avatar nzSrc="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"></nz-avatar>
</ng-template>
<ng-template #coverTemplate>
<img alt="example" [src]="item.pic" />
</ng-template>
</nz-list-item>
</ng-template>
</nz-list>
</div>
渲染搜索的音乐列表和播放音乐
新建播放组件
ng g c music
导入APlayer
:
import APlayer from 'APlayer';
并在ngOnInit
生命周期内实例化APlayer
const List = JSON.parse(sessionStorage.getItem("musicList"));
const ap = new APlayer({
container: document.getElementById('aplayer'),
audio: List
});
ap.list.switch(this.index);//切换至列表页点击的歌曲
其中sessionStorage.getItem("musicList")
获取列表页搜索到的歌曲,赋值给Aplayer中的audio字段。实现列表展示。
ap.list.switch(this.index),其中switch是展示列表页面点击的歌曲索引,实现播放点击的歌曲。this.index为列表传递过来的:
musiclist.component.ts跳转播放页并传递数据:
playMusic(index: any) {
console.log(index);
let list = [];
this.MusicList.forEach(item => {
list.push({
name: item.title,
artist: item.author,
url: item.url,
cover: item.pic,
theme: '#ebd0c2'
})
})
sessionStorage.setItem("musicList", JSON.stringify(list));
this.router.navigate(['music'],{
queryParams:{
index:index
}
})
}
歌曲播放获取列表传递过来的index数据 :
constructor(private activeRoute: ActivatedRoute) {
activeRoute.queryParams.subscribe(params => {
this.index = params.index;
})
}
播放歌曲完整:
import { Component, OnInit } from '@angular/core';
import APlayer from 'APlayer';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-music',
templateUrl: './music.component.html',
styleUrls: ['./music.component.scss']
})
export class MusicComponent implements OnInit {
index = ""
constructor(private activeRoute: ActivatedRoute) {
activeRoute.queryParams.subscribe(params => {
this.index = params.index;
})
}
ngOnInit() {
const List = JSON.parse(sessionStorage.getItem("musicList"));
const ap = new APlayer({
container: document.getElementById('aplayer'),
audio: List
});
ap.list.switch(this.index);//切换至列表页点击的歌曲
}
}
跳转播放页面:
总结
该Demo,麻雀虽小,五脏俱全,其 结合使用了angular基本的指令、管道、数据双向绑、事件、 http的封装统一拦截响应处理,路由的定义、使用,以及组件的引入,服务引入和编写、模板的编写等等Angular技术,rxjs 的使用,ng-zorro的使用。
其中有使用不正确,或者有更好的建议,欢迎指正~