最近闲暇时在使用Electron做桌面端应用(仿网易云桌面客户端)于是有接触到audio。由于很久没有写过这标签了 特来此详细做个笔记,方便自己以后查阅。
先放一个auido标签 让他动起来
<audio
:src="https://music.163.com/song/media/outer/url?id=65847.mp3"
controls
></audio>
一、Audio 对象
Audio 对象属性
属性 | 描述 | 博主提示 |
---|---|---|
audioTracks | 返回表示可用音频轨道的 AudioTrackList 对象。 | 任何主流浏览器都不支持 audioTracks 属性。 |
autoplay | 设置或返回是否在就绪(加载完成)后随即播放音频。 | 如果设置了该属性,音频(加载完成)将自动播放。 |
buffered | 返回表示音频已缓冲部分的 TimeRanges 对象。 | |
controller | 返回表示音频当前媒体控制器的 MediaController 对象。 | 目前没有主流浏览器支持 controller 属性。 |
controls | 设置或返回音频是否应该显示控件(比如播放/暂停等)。 | 设置就可以显示控件,但是每个浏览器都有自己显示auido的样式 |
crossOrigin | 设置或返回音频的 CORS 设置。 | 这个确实没太懂哈 按常理,跨域在头部设置或者config配置 或者后端配置 |
currentSrc | 返回当前音频的 URL。 | 只读 |
currentTime | 设置或返回音频中的当前播放位置(以秒计)。 | 可写可读 |
defaultMuted | 设置或返回音频默认是否静音。 | 可写可读 |
defaultPlaybackRate | 设置或返回音频的默认播放速度。 | 可写可读 |
duration | 返回音频的长度(以秒计)。 | 只读 |
ended | 返回音频的播放是否已结束。 | 只读 |
error | 返回表示音频错误状态的 MediaError 对象。 | |
loop | 设置或返回音频是否应在结束时再次播放。 | 可写可读 |
mediaGroup | 设置或返回音频所属媒介组合的名称。 | 可写可读 |
muted | 设置或返回是否关闭声音。 | 可写可读 |
networkState | 返回音频的当前网络状态。 | 0 - 音频尚未初始化;1 - 音频是活动的且已选取资源,但并未使用网络2 - 浏览器正在下载数据;3 - 未找到音频来源 |
paused | 设置或返回音频是否暂停。 | 只读 |
playbackRate | 设置或返回音频播放的速度。 | 可写可读,例值:1.0 正常速度;0.5 半速(更慢);2.0 倍速(更快);-1.0 向后;正常速度-0.5 向后半速 等 |
played | 返回表示音频已播放部分的 TimeRanges 对象。 | |
preload | 设置或返回音频的 preload 属性的值。 | 可写可读,是否在页面加载后载入音频。 |
readyState | 返回音频当前的就绪状态。 | 可写可读 |
seekable | 返回表示音频可寻址部分的 TimeRanges 对象。 | |
seeking | 返回用户当前是否正在音频中进行查找。 | |
src | 设置或返回音频的 src 属性的值。 | 可写可读 |
textTracks | 返回表示可用文本轨道的 TextTrackList 对象。 | |
volume | 设置或返回音频的音量。 | 规定音频/视频的当前音量。必须是介于 0.0 与 1.0 之间的数字。可写可读 |
Audio 对象方法
方法 | 描述 |
---|---|
addTextTrack() | 向音频添加新的文本轨道。 |
canPlayType() | 检查浏览器是否能够播放指定的音频类型。 |
fastSeek() | 在音频播放器中指定播放时间。 |
getStartDate() | 返回新的 Date 对象,表示当前时间线偏移量。 |
load() | 重新加载音频元素。 |
play() | 开始播放音频。 |
pause() | 暂停当前播放的音频。 |
二、播放器代码
template
<div class="audio">
<audio @ended="next(currentSongUnit.afterId)" ref="audio" @timeupdate="timeupdate"
preload="auto" :src="audioSrc" />
<div class="audio-btn fac">
<!-- 上一首 -->
<i @click="next(currentSongUnit.beforeId)"class="iconfont icon-lastSong"/>
<!-- 播放 -->
<i @click="play()" v-show="isPause" class="iconfont icon-play" />
<!-- 暂停 -->
<i @click="stop()" v-show="!isPause" class="iconfont icon-paused" />
<!-- 下一首 -->
<i @click="next(currentSongUnit.afterId)" class="iconfont icon-nextSong"/>
</div>
<div class="audio-progressBar fbc">
<!-- 歌曲当前播放时间 -->
<p class="start-tiem audio-tiem">{{ staratTime }}</p>
<!-- 进度条 -->
<div>
<el-slider v-model="progressBarValue" :show-tooltip="false" @change="sliderChange"/>
</div>
<!-- 歌曲总时长 -->
<p class="end-tiem audio-tiem">{{ allTime }}</p>
</div>
</div>
script
#部分代码涉及接口 接口我并没有写出来 不好意思
<script>
import { search, getSongDetail } from '@/api/find';
export default {
name: 'myFooter',
components: {},
data() {
return {
audio: '',//audio的ref
hotList: [],//歌曲完整列表
staratTime: '00:00', //当前播放时间
progressBarValue: 0,//进度条显示长度 默认为0 范围为0-100 使用前转换
allTime: '00:00', //歌曲总时间
isPause: true, //是否暂停 默认暂停
songsIdList: [], //所有歌曲简化信息
currentSongUnit: {}, //当前歌曲部分信息
};
},
computed: {
//歌曲的url
audioSrc() {
return `https://music.163.com/song/media/outer/url?id=${this.currentSongUnit.id}.mp3`;
},
},
watch: {
//当歌曲audioSrc 发生变化时 重新执行load加载歌曲及 getSongDetail获取歌曲相信信息
audioSrc() {
this.audio.load();
this.getSongDetail();
},
},
mounted() {
this.audio = this.$refs.audio; //获取audio的ref
this.searchMusic();
},
methods: {
//search接口获取陈奕迅的歌单数据 重写数组 只保留id 名字 上/下首歌曲id
async searchMusic() {
const params = { keywords: '陈奕迅' };
const { result } = await search(params);
const hotList = result.songs;
//获取上一曲下一曲id 当前歌曲id,name 重置id数组
const songsIdList = hotList.map((item, index) => {
const afterId = hotList[index + 1] ? hotList[index + 1].id : null;
const beforeId = hotList[index - 1] ? hotList[index - 1].id : null;
const arr = { id: item.id, name: item.name, afterId, beforeId };
return arr;
});
this.hotList = hotList;//获取到的歌单信息
this.songsIdList = songsIdList;//重写的数组
this.currentSongUnit = songsIdList[0];//默认当前播放为第一条
this.getSongDetail();//执行getSongDetail
},
//getSongDetail接口获取当前播放歌曲的详细信息 歌单信息内歌曲list信息不够完善
async getSongDetail() {
const { songs } = await getSongDetail(this.currentSongUnit.id);
const song = songs[0];
//处理song.ar对象内歌手大于一位时 拼接/ 例: 陈奕迅/薛之谦
const singer = song.ar.length > 1
? song.ar.map((it) => it.name).join(' / ')
: song.ar[0].name;
this.currentSongUnit = {
...this.currentSongUnit,
songName: song.name,
songAvatar: song.al.picUrl,
singer,
};
this.play();//执行play方法 播放
},
//下一首 上一首 播放完毕也回执行该方法
next(id) {
if (!id) { return false; }
const nextList = this.songsIdList.find((it) => it.id === id);
this.currentSongUnit = nextList;
},
//暂停
stop() {
this.audio.pause();
this.isPause = true;
},
//播放 获取完整时间
play() {
this.allTime = this.filterDuration(this.audio.duration);
this.audio.play();
this.isPause = false;
},
//当歌曲实时播放时 获取当前播放时间 设置滚动条位置
timeupdate() {
this.staratTime = this.filterDuration(this.audio.currentTime);
this.progressBarValue =
(this.audio.currentTime / this.audio.duration) * 100;
// console.log(this.audio.currentTime / this.audio.duration);
},
//拉动滚动条时候出发 松手触发
sliderChange(e) {
this.audio.currentTime = (e / 100) * this.audio.duration;
},
// 静音/禁止静音
muted() {
this.audio.muted = !this.audio.muted;
},
//转化时长显示
filterDuration(s) {
if (typeof s !== 'number') {
throw new Error('传入时长需为数字类型');
}
let hour = Math.floor(s / 3600);
let min = Math.floor((s % 3600) / 60);
let sec = Math.floor(s % 60);
hour = hour < 10 ? `0${hour}` : hour;
min = min < 10 ? `0${min}` : min;
sec = sec < 10 ? `0${sec}` : sec;
return `${min}:${sec}`;
},
},
};
</script>