歌曲详情
歌曲的详情页面只是个展示页面,唯一的功能就是即时播放按钮。功能和逻辑都与之前的歌单详情一致。
- 创建song-info组件
ng g m song-info --routing
ngng c song-info
- song-info-routing.moduel.ts
const routes: Routes = [
{ path: 'songInfo/:id', component: SongInfoComponent, data: { titel: '歌曲详情' }, resolve: { songInfo: SongInfoResolverService } }
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
providers: [SongInfoResolverService]
})
在路由守卫中就有些不一样了,因为获取歌曲详情的API中并没有歌曲的歌词,所以守卫中就需要同时获得选中歌曲的信息以及选中歌曲的歌词
- song-info-resolver.service.ts
constructor( private songeServe: SongService ) { }
resolve (route: ActivatedRouteSnapshot): Observable<SongDataModel> {
const id = route.paramMap.get('id');
return forkJoin([
this.songeServe.getSongDetail(id),
this.songeServe.getLyric(Number(id))
]).pipe(first())
}
- sing-info.component.html
<div class="song-info wrap feature-wrap">
<div class="g-wrap6">
<div class="m-info clearfix">
<div class="cover">
<img [src]="song.al.picUrl" [alt]="song.name">
<div class="mask"></div>
</div>
<div class="cnt">
<div class="cntc">
<div class="hd clearfix">
<i class="f-pr"></i>
<div class="tit">
<h2 class="f-ff2 f-brk">{{song.name}}</h2>
</div>
</div>
<div class="user f-cb">
<div class="singers clearfix">
<span>歌手:</span>
<ul class="clearfix">
<li *ngFor="let singer of song.ar; last as isLast">
<a [routerLink]="['/singer', singer.id]">{{singer.name}}</a>
<i [hidden]="isLast">/</i>
</li>
</ul>
</div>
<div class="al">
<span>所属专辑:</span>
<span class="al-name">{{song.al.name}}</span>
</div>
</div>
<div class="btns">
<nz-button-group class="btn">
<button class="play" nz-button nzType="primary" (click)="onAddSong(song,true)">
<i nz-icon nzType="play-circle" nzTheme="outline" ></i>播放
</button>
<button class="add" nz-button nzType="primary" (click)="onAddSong(song)">+</button>
</nz-button-group>
<button class="btn like" nz-button nzType="primary"><span>收藏</span></button>
<button class="btn share" nz-button nzType="primary"><span>分享</span></button>
</div>
<div class="lyric-info f-brk">
<div class="lyric-content" [class.expand]="controlLyric.isExpand">
<div class="lyric-line" *ngFor="let item of lyric">
<p>{{item.txt}}</p>
<p>{{item.txtCn}}</p>
</div>
</div>
<div class="toggle-expand" (click)="toggleLyric()">
<span>{{controlLyric.label}}</span>
<i nz-icon [nzType]="controlLyric.iconCls" nzTheme="outline"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
- sing-info.component.ts
// 动态展开
controlLyric = {
isExpand: false,
label: '展开',
iconCls: 'down'
}
song: Song;
lyric: BaseLyricLine[];
currentSong: Song;
private destroy$ = new Subject<void>();
constructor(
private route: ActivatedRoute,
private store$: Store<AppStoreModule>,
private songServe: SongService,
private message: NzMessageService,
private batchActionServe: BatchActionsService,
) { }
ngOnInit () {
this.route.data.pipe(map(res => res.songInfo)).subscribe(([song, lyric]) => {
this.song = song;
this.lyric = new WyLyric(lyric).lines;
this.listenCurrent();
})
}
// 监听当前歌曲变化,当页面销毁时解绑
listenCurrent () {
this.store$.pipe(select(getPlayer), select(getCurrentSong), takeUntil(this.destroy$)).subscribe(song => {
this.currentSong = song;
})
}
// 展开/折叠
toggleLyric () {
this.controlLyric.isExpand = !this.controlLyric.isExpand;
if (this.controlLyric.isExpand) {
this.controlLyric.label = '收起';
this.controlLyric.iconCls = 'up'
} else {
this.controlLyric.label = '展开';
this.controlLyric.iconCls = 'down'
}
}
// 添加/播放歌曲
onAddSong (song: Song, isPlay = false) {
if (!this.currentSong || this.currentSong.id !== song.id) {
this.songServe.getSongList(song).subscribe(res => {
if (res.length) {
this.batchActionServe.insertSong(res[0], isPlay);
} else {
this.message.error('NO URL')
}
})
}
}
ngOnDestroy (): void {
this.destroy$.next();
this.destroy$.complete();
}
逻辑几乎与歌单列表一致,所以这个模块的难度在css样式上!