技術棧
angular8+ngrx8+ng-zorro+material/odk
ng模塊化設計/proxy,http攔截器/依賴注入/自定義指令和管道、自定義表單控件/動態組件/rxjs操作符/變更檢測策略/ngrx8
api:
創建項目
依賴 | 步驟 | 報錯/效果 |
ng-zorro |
npm install rxjs@^6.5.2 |
只出現fsevents的WARN可忽略 |
npm install ng-zorro-antd --save //安裝到本地 |
8.3.1版本需要依賴rxjs@^6.5.2 |
|
ng add ng-zorro-antd //項目中添加 |
? Add icon assets [ Detail: https://ng.ant.design/components/icon/en ] Yes found 1 high severity vulnerability |
|
ng serve --open //重啓項目 |
頁面變成ng-zorro則爲成功 | |
<button nz-button nzType="primary">button</button> | 使用ng-zorro | |
minireset |
npm install minireset //安裝minireset |
出現fseven警告可hulue |
@import '~minireset.css'; //樣式文件中引用 |
使用minireset |
頁面結構、模塊化設計
文件類型 | 步驟 | 解釋 |
style文件 |
style樣式文件位置: 1.手動剪切style.css黏貼到assets/styles 2.angular.json上改樣式的配置,包括"projects"下“styles”和"test"下“styles”路徑都要改爲src/assets/styles/index.css 3.ctrl+c退出再重新npm server --open |
|
module |
創建module ng g module core |
|
route |
ng g module app-routing --flat --module=app |
--flat 把這個文件放進了 src/app 中,而不是單獨的目錄中。 --module=app 告訴 CLI 把它註冊到 AppModule 的 imports 數組中。 |
輪播圖數據+推薦歌單數據+入駐歌手數據
知識點:自定義pipe,get請求+傳參,resolve守衛
步驟 | |||
獲取數據 | 接口 | services.module.ts | common.type.ts |
下載 clone API的庫 安裝依賴 npm install 運行 node ./app.js |
export const API_CONFIG=new InjectionToken('ApiConfigToken') @NgModule({ providers:[ {provide:API_CONFIG,useValue :'http://localhost:3000/'} ] }) |
創建 services/data-types/common.type.ts 數據原形 export type Banner={ targetId:number; url:string; imageUrl:string } export type Singer={ id:number; name:string; picUrl:string; albumSize:number; } export type SongSheet={ id:number; name:string; picUrl:string; playCount:number; /*tracks:Song[]*/ } |
|
服務home.service.ts |
服務singer.service.ts |
||
創建服務 ng g s services/home 引入 import { Banners } from './data-type/comment.type'; import { ServicesModule, API_CONFIG } from './services.module'; @Injectable({ providedIn: ServicesModule }) http請求 export class HomeService { constructor(private http:HttpClient,@Inject(API_CONFIG) private uri:string) {} goBanners():Observable<Banners[]>{ return this.http.get(this.uri+'banner') .pipe(map((res:{banners:Banners[]})=> res.banners)) } getPersonalSheetList():Observable<SongSheet[]>{ return this.http.get(this.uri+'personalized') .pipe(map((res:{result:SongSheet[]})=> res.result.slice(0,16))) } } |
創建服務 ng g s services/singer 數據 type SingerParams={ offset:number; limit:number; cat?:string } const defaultParams:SingerParams={ offset:0, limit:9, cat:'5001' } get請求加傳參 getEnterSinger(args:SingerParams=defaultParams) :Observable<Singer[]{ const params=new HttpParams({ fromString: queryString.stringify(args) }); return this.http.get(this.uri+'artist/list',{ params }) .pipe(map((res:{artists:Singer[]})=> res.artists)) |
||
守衛home-resolve.service.ts | |||
創建守衛 home目錄下創建home-resolve.service.ts 引入HomeService import { HomeService } from 'src/app/services/home.service'; import {Banners} from '../../services/data-type/comment.type' @Injectable() 數據類型 type HomeDataType = [Banners[],HotTag[],SongSheet[],Singer[]]; @Injectable() 繼承守衛 export class HomeResolveServices implements Resolve<HomeDataType>{ 引入服務,調用方法 constructor(private homeServe:HomeService,private singerService:SingerService){} resolve():Observable<HomeDataType>{ return forkJoin([ //線程池 this.homeServe.goBanners(), this.homeServe.goHotTag(), this.homeServe.getPersonalSheetList(), this.singerService.getEnterSinger() ]).pipe(first()) } } |
|||
路由home-routing.module.ts | 組件中home.component.ts | ||
引入守衛,傳入內容 Routers:[ {path:"home",component:HomeComponent,data:{title:"首頁"},resolve:{homeData:HomeResolveServices}} ] |
private banners:any; 獲取數據 constructor(private route:ActivatedRoute) { this.route.data.pipe(map(res => res.homeData)).subscribe (([banners,hotTags,songSheetlist,singers]) =>{ this.banners=banners; this.hotTag=hotTags; this.SongSheet=songSheetlist; this.Singers=singers; }); |
輪播圖
輪播組件 | home.component.html父 | carousel.component.html子 | |
<div class="home"> <app-carousel #myCarousel [activeIndex]="beforeChangeN" //1.6父傳子(changeSlide)="onChangeSlide($event)"> //2.3父方法傳給子 <nz-carousel nzAutoPlay nzEffect="fade" [nzDotRender]="myCarousel.dotRet" //1.3渲染模板並傳出參數number (nzBeforeChange)="onBeforeChange($event)"> //1.4父獲取輪播回調的數據 <div nz-carousel-content *ngFor="let item of banners" class="carousel" > <a [href]="item.url"> <img [src]="item.imageUrl"/> </a> </div> </nz-carousel> </app-carousel> </div> |
創建 ng g c pages/home/components/carousel 內容 <div class="carousel"> <div class="wrap"> <i nz-icon nzType="left" nzTheme="outline" class="arrow left"></i> <ng-content></ng-content> <ng-template #dot let-number> //1.1模板 傳入參數 <i class="dot" [class.active]="activeIndex===number" (click)="onChangeSlideData('pre')"></i> //2.5觸發子方法 </ng-template> <i nz-icon nzType="right" nzTheme="outline" class="arrow right" (click)="onChangeSlideData('next')"></i> </div> </div> |
||
home.component.ts | carousel.component.ts | ||
beforeChangeN:any; @ViewChild(NzCarouselComponent,{static:true}) private nzCarousel:NzCarouselComponent; //2.1獲取輪播組件 onBeforeChange({to}){ //1.5父獲取輪播回調的數據 this.beforeChangeN=to; } onChangeSlide(type:string){ //2.2定義父方法,觸發輪播方法 this.nzCarousel[type](); } |
//1.2獲取模板 @ViewChild('dot',{static:true}) dotRet:TemplateRef<any>; @Input() activeIndex=0; //1.7子接收父傳來的回調 //2.4子觸發父方法並傳值 @Output() changeSlide=new EventEmitter<string>(); // onChangeSlideData(type:string){ this.changeSlide.emit(type); } |
||
原點替換 | home.component.html父 | carousel.component.html子 | |
<app-carousel #myCarousel> <nz-carousel [nzDotRender]="myCarousel.dotRet" > //1.3渲染模板並傳出參數number </nz-carousel> </app-carousel> |
<ng-template #dot let-number> //1.1模板 傳入number參數 </ng-template> |
||
home.component.ts | carousel.component.ts | ||
X |
//1.2獲取模板 @ViewChild('dot',{static:true}) dotRet:TemplateRef<any>; |
||
[nzDotRender]是Dot渲染模板,類型爲TemplateRef | |||
原點觸發 |
home.component.html父 | carousel.component.html子 | |
<app-carousel #myCarousel [activeIndex]="beforeChangeN" >//1.6父將數據傳給子 <nz-carousel (nzBeforeChange)="onBeforeChange($event)"> //1.4輪播組件回調的數據傳給home組件 </nz-carousel> </app-carousel> |
//子使用數據 <i class="dot" [class.active]="activeIndex===number" ></i> |
||
home.component.ts | carousel.component.ts | ||
beforeChangeN:any; onBeforeChange({to}){ //1.5home組件接收輪播回調的數據 this.beforeChangeN=to; } |
@Input() activeIndex=0; //1.7子接收父傳來的回調 | ||
(nzBeforeChange) 是輪播組件切換面板的回調函數,可以傳出輪播數據EventEmitter<{ from: number; to: number }> | |||
箭頭觸發 | home.component.html父 | carousel.component.html子 | |
<app-carousel (changeSlide)="onChangeSlide($event)"> //2.3父方法傳給子 </app-carousel> |
<i (click)="onChangeSlideData('pre')"></i> //2.5觸發子方法 <i (click)="onChangeSlideData('next')"></i> |
||
home.component.ts | carousel.component.ts | ||
@ViewChild(NzCarouselComponent,{static:true}) private nzCarousel:NzCarouselComponent; //2.1獲取輪播組件 onChangeSlide(type:string){ //2.2定義父方法,觸發輪播方法 this.nzCarousel[type](); } |
@component({ ntg }) //觸發時進行變更檢測 /2.4子觸發父方法並傳值 @Output() changeSlide=new EventEmitter<string>(); onChangeSlideData(type:string){ this.changeSlide.emit(type); }
|
||
NzCarouselComponent中的next()和pre()方法用作切換面板 |
播放器
推薦歌單點擊播放 | home.component.html父 | singer-sheet.component.html子 |
3.父方法傳給子 <app-singer-sheet *ngFor="let item of SongSheet" [sheet]="item" (onPlay)="onPlaySheet($event)" ></app-singer-sheet> |
1.觸發子方法(傳入歌單id) <i class="icon play" (click)="playSheet(sheet.id)"> |
|
home.component,ts父 | singer-sheet.component.ts子 | |
4觸發getSongSheetDetail方法 constructor(private sheetServe:SheetServices) onPlaySheet(id:number){ this.sheetServe.getSongSheetDetail(id).subscribe(res =>{console.log(res)}) } |
2.子向父傳參 @output onPlay=new EventEmitter<number>(); playSheet(id:number){ this.onPlay.emit(id); } |
|
SheetServices服務 | SongServices服務 | |
6.獲取歌單列表詳情(get+HttpParams傳參) getSongSheetDatail(id:number): Observable<SongSheet>{ const params=new HttpParams().set('id',id.toString()); return this.http.get(this.uri+'playlist/detail',{ params }) .pipe(map((res:{playlist:SongSheet})=> res.playlist)) } 5. 觸發getSongSheetDetail 篩選出song[]並賦值給getSongList playSheet(id: number): Observable<Song[]> { return this.getSongSheetDetail(id) .pipe(pluck('tracks'), switchMap(tracks => this.SongServer.getSongList(tracks))); } |
8.獲取音樂URL getSongUrl(ids: string): Observable<SongUrl[]> { const params = new HttpParams().set('id', ids); return this.http.get(this.uri + 'song/url', { params }) .pipe(map((res: { data: SongUrl[] }) => res.data)); } 7.找出所有id對應的Url並把song[]和url數組傳給拼接函數 getSongList(songs: Song | Song[]): Observable<Song[]> { const songArr = Array.isArray(songs) ? songs.slice() : [songs]; const ids = songArr.map(item => item.id).join(','); return this.getSongUrl(ids).pipe(map(urls => this.generateSongList(songArr, urls))); } 9.拼接函數: private generateSongList(songs: Song[], urls: SongUrl[]): Song[] { const result = []; songs.forEach(song => { const url = urls.find(songUrl => songUrl.id === song.id).url; if (url) { result.push({ ...song, url }); } }); return result; } |
|
數據類型 | 解釋 | |
export type SongSheet={ id:number; //歌單id name:string; picUrl:string; playCount:number; tracks:Song[] } export type Song={ id:number; //歌曲id name:string; url:string; ar:Singer[]; al:{id:number,name:string;picUrl:string}; dt:number } export type SongUrl={ id:number; url:string } |
首先獲取指定id的歌單詳情getSongSheetDetail 篩選出歌單內所有歌曲信息trucks:song[]
|
|
播放面板
搜索組件
登錄
個人中心
收藏功能
分享功能
註冊功能