目的功能:
- axios 请求获取歌曲的 url 以及 封面照片
- 切换歌曲
- 歌单的展示
演示:
网易云音乐接口 github地址
https://github.com/Binaryify/NeteaseCloudMusicApi
安装
git clone git@github.com:Binaryify/NeteaseCloudMusicApi.git
在他的目录下
npm install
运行
node app.js
运行后我么可以在
http://localhost:3000/
打开文档
借此我们可以请求歌单和歌曲的 url 地址 , 歌曲照片地址等等,详细功能可以自己查看
以上全部借助别人的 api 接口
这里重点强调一下 获取歌曲 url 的 api
需要传入歌曲的 id 返回 url 地址
template
<template><div class="music-container" ref="music-container"><p v-show="isShowList">歌单: {{ belong }}</p><div class="music-audio"><audio ref="audio" autoplay="autoplay" :src="songsList[currentIndex].url" loop="loop"></audio><img :src="songsList[currentIndex].picUrl" alt="" style="width: 60px; height: 60px;border-radius: 50%;" ref="audio-pic" @click="playMusic()"></div><ul><li @click="showList"><span v-if="isShowList">关闭播放列表</span><span v-else>打开</span></li><li v-for="(item, index) in songsList" @click="playMusic(index)" v-show="isShowList"><span>{{ item.name }}</span> <span>{{ item.ar + "" }}</span></li></ul></div>
</template>
这里需要修改为你自己的信息
<script>
import axios from "axios"
export default {name: 'App',components: {},data: function () {return {// 歌曲名称 歌曲url 照片url 作者名称songsList: [{name: '未知', url: '', picUrl: '', ar: ''}],currentIndex: 0,belong: '',musicTimer: null,musicTime: 0,isShowList: true}},methods: {//showList:function () {this.isShowList = !this.isShowListif (!this.isShowList) {this.$refs["music-container"].style.width = "90px"this.$refs["music-container"].style.height = "120px"this.$refs["music-container"].style.transition = "1s"} else {this.$refs["music-container"].style.width = "270px"this.$refs["music-container"].style.height = ""}},// 控制音乐播放playMusic: function (index) {if (index === undefined) {} else if (this.currentIndex !== index) {this.currentIndex = indexthis.musicTime = 0return true;}if (this.$refs.audio.paused) {this.$refs.audio.play()this.isPlaying = !this.isPlayingthis.musicTimer = setInterval(() => {this.musicTime += 1this.$refs["audio-pic"].style.transform = "rotate(" + this.musicTime + "deg)";},100)return true;}else {this.$refs.audio.pause()clearInterval(this.musicTimer)this.$refs["audio-pic"].style.transitionDuration = this.musicTime;}},/*** 音乐,网络请求* */// 获取用户的 idgetUserId:function () {// 网易云接口axios.get('http://localhost:3000/login/cellphone?phone=修改为你的电话&password=修改为你的密码').then(res => {this.getList(res.data.account.id)})},// 获取用户的歌单getList:function (id) {axios.get('http://localhost:3000/user/playlist', {params: {uid: id}}).then(res => {// 选择要选择的歌单this.belong = res.data.playlist[1].namethis.getSongsId(res.data.playlist[1].id)})},// 获取歌单中 歌的id, 名字, 照片路径// 一次最多请求十首歌曲getSongsId:function (id) {axios.get('http://localhost:3000/playlist/track/all', {params: {id: id,limit: 10}}).then((res) => {// console.log(res.data.songs)// console.log(res.data.songs[0].name)// console.log(res.data.songs[0].id)// console.log(res.data.songs[0].al.picUrl)this.getSongs(res.data.songs)})},// 获取音乐getSongs:function (res) {for (let i = 0; i < res.length; i++) {// console.log(res[i].name)// console.log(res[i].id)// console.log(res[i].al.picUrl)this.getSong(res[i])}console.log(this.songsList)},getSong:function(items) {axios.get('http://localhost:3000/song/url', {params: {id: items.id}}).then(res => {console.log(res.data.data[0].url)if (this.songsList[0].name === '' || this.songsList[0].name === '未知') {this.songsList[0].name = items.namethis.songsList[0].url = res.data.data[0].urlthis.songsList[0].picUrl = items.al.picUrlthis.songsList[0].ar = items.ar.map(it => {return it.name})} else {this.songsList.push({name: items.name,url: res.data.data[0].url,picUrl: items.al.picUrl,ar: items.ar.map(it => {return it.name})})}})}},mounted() {// 获取音乐this.getUserId()}
}
</script>
样式的话,自己玩去
<style lang="less" scoped>
* {padding: 0;margin: 0;box-sizing: border-box;
}
.music-container {text-align: center;color: #bbbbbb;width: 270px;background-color: transparent;border: 1px solid black;border-radius: 20px;
}.music-audio {width: 100%;display: flex;& > img {margin: 10px;}& > span {margin: auto;}
}button {width: 20px;height: 20px;border-radius: 50%;outline: none;background-color: transparent;border: none;color: #bbbbbb;
}ul {width: 100%;list-style: none;display: flex;flex-direction: column;border-top: 1px solid black;font-size: 8px;color: #bbbbbb;li {padding: 10px 0;border-bottom: 1px solid black;display: flex;justify-content: space-evenly;align-items: center;span {width: 40%;text-align: center;overflow: hidden;white-space: nowrap;text-overflow-ellipsis: ellipsis;}}& > li:last-child {border-bottom: none;}& > li:first-child {border-bottom: none;}
}
目录结构
vue.config.js
// vue.config.js
const path = require('path');
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV);
const resolve = (dir) => path.join(__dirname, dir);
module.exports = {chainWebpack: config => {config.resolve.symlinks(true); // 修复热更新失效// 如果使用多页面打包,使用vue inspect --plugins查看html是否在结果数组中config.plugin("html").tap(args => {// 修复 Lazy loading routes Errorargs[0].chunksSortMode = "none";return args;});config.resolve.alias // 添加别名.set('@', resolve('src')).set('@assets', resolve('src/assets')).set('@components', resolve('src/components')).set('@views', resolve('src/views')).set('@store', resolve('src/store'));},devServer: {overlay: { // 让浏览器 overlay 同时显示警告和错误warnings: true,errors: true},host: "localhost",port: 8081, // 端口号https: false, // https:{type:Boolean}open: true, //配置自动启动浏览器hotOnly: true, // 热更新// proxy: 'http://localhost:8080' // 配置跨域处理,只有一个代理proxy: { //配置多个跨域"/api": {target: "http://172.11.11.11:3000",changeOrigin: true,// ws: true,//websocket支持secure: false,pathRewrite: {"^/api": "/"}}}}
}
bable.config,js
module.exports = module.exports = {presets: [ '@vue/cli-plugin-babel/preset' ],"plugins": [["component",{"libraryName": "element-ui","styleLibraryName": "theme-chalk"}]]
}
App.vue
<template><div id="app"><music-container></music-container></div>
</template><script>
import MusicContainer from "./components/MusicContainer";
export default {name: 'App',components: {MusicContainer}
}
</script><style lang="less">
* {padding: 0;margin: 0;box-sizing: border-box
}
body {height: 100vh;width: 100vw;background-image: url("~@/assets/b.jpg");background-repeat: no-repeat;background-size: cover;background-position: center;
}
</style>
and 附加视频播放器的思路
<!DOCTYPE html>
<html>
<head lang="en"><meta charset="UTF-8"><title></title><!-- 引入字体图标的文件--><link rel="stylesheet" href="css/font-awesome.min.css"/><style>*{margin: 0;padding: 0;}/*多媒体标题*/figcaption{text-align: center;line-height: 150px;font-family: "Microsoft Yahei";font-size:24px;}/* 播放器*/.palyer{width: 720px;height: 360px;margin:10px auto;border: 1px solid #000;background: url(images/loading.gif) center no-repeat #000;background-size:auto 100%;position: relative;border-radius: 20px;}.palyer video{height:100%;display: block;margin:0 auto;/*display: none;*/}/* 控制条*/.controls{width: 700px;height:40px;background-color: rgba(255, 255, 0, 0.3);position: absolute;bottom:10px;left:10px;border-radius: 10px;}/*开关*/.switch{position: absolute;width: 20px;height: 20px;left:10px;top:10px;text-align: center;line-height: 20px;color:yellow;}/*进度条*/.progress{width: 432px;height: 10px;position: absolute;background-color: rgba(255,255,255,0.4);left:40px;top:15px;border-radius: 4px;overflow: hidden;}/* 当前进度*/.curr-progress{width: 50%;height: 10px;background-color: #fff;}/* 时间模块*/.time{width: 120px;height: 20px;text-align: center;line-height: 20px;color:#fff;position: absolute;left:510px;top:10px;font-size:12px;}/*全屏*/.extend{position: absolute;width: 20px;height: 20px;right:20px;top:10px;text-align: center;line-height: 20px;color:yellow;}</style>
</head>
<body><!-- 多媒体--><figure><!-- 多媒体标题--><figcaption>视频案例</figcaption><div class="palyer"><video src="video/fun.mp4"></video><!-- 控制条--><div class="controls"><!-- 播放暂停--><a href="#" class="switch icon-play"></a><div class="progress"><!-- 当前进度--><div class="curr-progress"></div></div><!-- 时间--><div class="time"><span class="curr-time">00:00:00</span>/<span class="total-time">00:00:00</span></div><!-- 全屏--><a href="#" class="extend icon-resize-full"></a></div></div></figure><script>// 思路:/** 1、点击按钮 实现播放暂停并且切换图标* 2、算出视频的总时显示出出来* 3、当视频播放的时候,进度条同步,当前时间同步* 4、点击实现全屏*/// 获取需要的标签var video=document.querySelector('video');
// 播放按钮var playBtn=document.querySelector('.switch');
// 当前进度条var currProgress=document.querySelector('.curr-progress');
// 当前时间var currTime=document.querySelector('.curr-time');
// 总时间var totalTime=document.querySelector('.total-time');
// 全屏var extend=document.querySelector('.extend');var tTime=0;// 1、点击按钮 实现播放暂停并且切换图标playBtn.onclick=function(){
// 如果视频播放 就暂停,如果暂停 就播放if(video.paused){
// 播放video.play();//切换图标this.classList.remove('icon-play');this.classList.add('icon-pause');}else{
// 暂停video.pause();
// 切换图标this.classList.remove('icon-pause');this.classList.add('icon-play');}}// 2、算出视频的总时显示出出来
// 当时加载完成后的事件,视频能播放的时候video.oncanplay=function(){
// 获取视频总时长tTime=video.duration;console.log(tTime);// 将总秒数 转换成 时分秒的格式:00:00:00
// 小时var h=Math.floor(tTime/3600);
// 分钟var m=Math.floor(tTime%3600/60);
// 秒var s=Math.floor(tTime%60);// console.log(h);
// console.log(m);
// console.log(s);// 把数据格式转成 00:00:00h=h>=10?h:"0"+h;m=m>=10?m:"0"+m;s=s>=10?s:"0"+s;console.log(h);console.log(m);console.log(s);
// 显示出来totalTime.innerHTML=h+":"+m+":"+s;}
// * 3、当视频播放的时候,进度条同步,当前时间同步
// 当时当前时间更新的时候触发video.ontimeupdate=function(){
// 获取视频当前播放的时间
// console.log(video.currentTime);
// 当前播放时间var cTime=video.currentTime;
// 把格式转成00:00:00var h=Math.floor(cTime/3600);
// 分钟var m=Math.floor(cTime%3600/60);
// 秒var s=Math.floor(cTime%60);// 把数据格式转成 00:00:00h=h>=10?h:"0"+h;m=m>=10?m:"0"+m;s=s>=10?s:"0"+s;// 显示出当前时间currTime.innerHTML=h+":"+m+":"+s;// 改变进度条的宽度: 当前时间/总时间var value=cTime/tTime;currProgress.style.width=value*100+"%";}// 全屏extend.onclick=function(){
// 全屏的h5代码video.webkitRequestFullScreen();}</script>
</body>
</html>
处理兼容性问题
为了做到多浏览器支持,可以采取以下兼容性写法:
<!--推荐的兼容写法:-->
<audio controls loop><source src="music/yinyue.mp3"/><source src="music/yinyue.ogg"/><source src="music/yinyue.wav"/>抱歉,你的浏览器暂不支持此音频格式
</audio>
代码解释:如果识别不出音频格式,就弹出那句“抱歉”。
补充视频兼容问题
HTML5通过<video>
标签来解决视频播放的问题。
使用举例:
<video src="video/movie.mp4" controls autoplay></video>
我们可以通过附加属性,来更友好地控制视频的播放,如:
-
autoplay
自动播放。写成autoplay
或者autoplay = ""
,都可以。 -
controls
控制条。(建议把这个选项写上,不然都看不到控件在哪里) -
loop
循环播放。 -
preload
预加载 同时设置 autoplay 时,此属性将失效。 -
width
:设置播放窗口宽度。 -
height
:设置播放窗口的高度。
由于版权等原因,不同的浏览器可支持播放的格式是不一样的:
兼容性写法:
<!--<video src="video/movie.mp4" controls autoplay ></video>--><!-- 行内块 display:inline-block --><video controls autoplay><source src="video/movie.mp4"/><source src="video/movie.ogg"/><source src="video/movie.webm"/>抱歉,不支持此视频</video>