[Angular实战网易云]——22、歌曲详情

本文介绍如何在Angular应用中创建歌曲详情页面,重点在于即时播放功能和页面样式设计。通过song-info组件来展示歌曲信息,同时在路由守卫中获取歌曲详情和歌词,实现逻辑与歌单详情类似。
摘要由CSDN通过智能技术生成

歌曲详情

歌曲的详情页面只是个展示页面,唯一的功能就是即时播放按钮。功能和逻辑都与之前的歌单详情一致。

  • 创建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样式上!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值