/* * Copyright (c) Baidu, Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import Icon from '@cosui/cosmic/icon'; import type {MusicPlayerProps, MusicPlayerEvents} from './interface'; import {MusicPlayerStatus, Status} from './interface'; import MusicPlayerBase from './base'; import {isURL} from '@cosui/cosmic/util'; export default class MusicPlayer extends MusicPlayerBase { static template = `
{{ name }}
下载
{{ title }}
{{ item.content }}
`; static components = { 'cos-icon': Icon }; static computed = { _isUrl(this: MusicPlayer): boolean { const icon = this.data.get('icon'); return isURL(icon); } }; private _onTimeUpdate: (e: Event) => void; private _onPlay: (e: Event) => void; private _onPause: (e: Event) => void; initData(): MusicPlayerProps { return { _playStatus: MusicPlayerStatus.PENDING, _currentLyricIndex: 0, _progress: 0, // 黑胶背景图 _vinyl: 'https://gips2.baidu.com/it/u=2059581208,4043524228&fm=3028&app=3028&f=PNG&fmt=auto&q=75&size=f544_544', icon: '', title: '', poster: '', lyrics: [], src: '', currentTime: 0, duration: 0, status: Status.FINISHED }; } attached() { const audio = this.ref('audio') as unknown as HTMLAudioElement; this._onTimeUpdate = this.onTimeUpdate.bind(this); this._onPlay = this.play.bind(this); this._onPause = this.pause.bind(this); audio.addEventListener('timeupdate', this._onTimeUpdate); audio.addEventListener('play', this._onPlay); audio.addEventListener('pause', this._onPause); } detached() { const audio = this.ref('audio') as unknown as HTMLAudioElement; if (audio) { audio.removeEventListener('timeupdate', this._onTimeUpdate); audio.removeEventListener('play', this._onPlay); audio.removeEventListener('pause', this._onPause); } } // 时间戳更新 + 滚动歌词 onTimeUpdate(event: any) { const audio = this.ref('audio') as unknown as HTMLAudioElement; const currentTime = event.currentTime || (audio.currentTime * 1000); const duration = event.duration || (audio.duration * 1000); // 更新进度条 const progress = (currentTime / duration) * 100; this.data.set('_progress', progress); // 更新歌词 const lyrics = this.data.get('lyrics') || []; const index = lyrics.findIndex( lyric => (lyric.startTime ?? 0) <= currentTime && currentTime < (lyric.endTime ?? Infinity) ); requestAnimationFrame(() => { if (index !== -1 && this.data.get('_currentLyricIndex') !== index) { this.data.set('_currentLyricIndex', index); this.scrollLyrics(index); } }); } // 滚动歌词,让当前高亮居中 scrollLyrics(index: number) { const lyrics = this.ref('lyricsWrapper') as unknown as HTMLElement; if (!lyrics) { return; } const lyricNodes = lyrics.querySelectorAll('.cosd-music-player-content-lyric'); const activeLyric = lyricNodes[index] as HTMLElement; if (!activeLyric) { return; } // 获取高亮元素和容器尺寸 const containerHeight = lyrics.clientHeight; const lineHeight = activeLyric.offsetHeight; // 获取高亮元素相对于容器位置 const lineRect = activeLyric.getBoundingClientRect(); const containerRect = lyrics.getBoundingClientRect(); const relativePosition = lineRect.top - containerRect.top; const scrollTop = relativePosition + lyrics.scrollTop - (containerHeight / 2) + (lineHeight / 2); lyrics.scrollTo({ top: scrollTop, behavior: 'smooth' }); } handleDownload(event: Event) { this.fire('download', {event}); } }