新建项目
在适合的目录下打开终端输入vue create music_player,回车
选择Default([Vue 2] babel,eslint)
等待项目构建完成
项目构建成功
安装路由
用vscode打开项目所在文件夹
新建终端输入命令npm install vue-router@3.5.2 –save
在src目录下新建文件夹router,并在其下新建文件index.js
在新建的文件index.js中写入路由模板代码,成为路由配置文件
javascript;gutter:true;
import Vue from 'vue'
import VueRouter from 'vue-router'</p>
<p>Vue.use(VueRouter)</p>
<p>const routes = []</p>
<p>const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})</p>
<p>export default router</p>
<pre><code>
在main.js中引入路由配置文件
;gutter:true;
import Vue from ‘vue’
import App from ‘./App.vue’
//引入路由
import router from ‘./router’
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
}).$mount(‘#app’)
在App.vue文件中清除多余代码,并写入全局路由组件
javascript;gutter:true;
export default {</p>
<p>}</p>
<p>/<em> 全局设置样式 </em>/
html,body,#app{
height: 100%;
}</p>
<pre><code>
## 安装vant组件库
在终端中输入npm install vant@latest-v2 -S
![vue+vant音乐播放器(andriod)项目](https://johngo-pic.oss-cn-beijing.aliyuncs.com/articles/20230605/2769044-20220713080713539-765606735.png)
在终端中输入npm install qs --save
![vue+vant音乐播放器(andriod)项目](https://johngo-pic.oss-cn-beijing.aliyuncs.com/articles/20230605/2769044-20220712234355239-827493764.png)
在src目录下新建文件夹plugins,并在其下新建文件vant.js
并写入代码
;gutter:true;
import Vue from ‘vue’
import Vant, { Locale } from ‘vant’
import ‘vant/lib/index.css’
Vue.use(Vant)
在main.js中引入vant.js
javascript;gutter:true;
import Vue from 'vue'
import App from './App.vue'
//引入路由
import router from './router'
//引入vant.js文件
import './plugins/vant.js'</p>
<p>Vue.config.productionTip = false</p>
<p>new Vue({
router,
render: h => h(App),
}).$mount('#app')</p>
<pre><code>
## 安装axios
在终端中输入npm install axios --save
![vue+vant音乐播放器(andriod)项目](https://johngo-pic.oss-cn-beijing.aliyuncs.com/articles/20230605/2769044-20220712234625193-101558161.png)
在src目录下新建文件夹http,并新建文件axios.js
并写入代码
;gutter:true;
import axios from ‘axios’
let baseUrl=’https://my-run-music-api.vercel.app’
/**
get方式请求
*/
export function get(addurl, data) {
return axios({
method: ‘get’,
url:baseUrl+addurl,
params:data, // get 请求时带的参数
})
}
export default axios
配置路由
在src下新建文件夹views,并新建文件Login.vue和Manage.vue
在新建的views目录下新建文件夹Home和Me
在新建的Home目录下新建文件home.vue和about.vue
在Me目录下新建文件me.vue
在src/router/index.js中写入代码
javascript;gutter:true;
import Vue from 'vue'
import VueRouter from 'vue-router'</p>
<p>Vue.use(VueRouter)</p>
<p>const routes = [
// 路由重定向 用户一次进入程序的时候 进入登录页面
{
path:'/',
redirect:'/login'
// redirect:'/manage/home'
},
// 登录页面的路由
{
path:'/login',
name:'Login',
component:()=>import('../views/Login.vue')
},
// 管理页面的路由
{
path:'/manage',
name:'Manage',
component:()=>import('../views/Manage.vue'),
// 配置子路由
children:[
// 首页
{
path:'home',
component:()=>import('../views/Home/home.vue')
},
// 我的页面
{
path:'me',
component:()=>import('../views/Me/me.vue')
},
// 关于页面
{
path:'about',
component:()=>import('../views/Home/about.vue')
}</p>
<pre><code>]
</code></pre>
<p>}
]</p>
<p>const router = new VueRouter({
// mode: 'history',
base: process.env.BASE_URL,
routes
})</p>
<p>export default router</p>
<pre><code>
## 一些问题的解决方案
### 在 vue eslint 报错 error "Component name "*****" should always be multi-word"
在vue.config.js文件中加入代码lintOnSave:false
;gutter:true;
const { defineConfig } = require(‘@vue/cli-service’)
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave:false
})
Vue中出现”**** is defined but never used”
在packagejson文件的rules里加入规则”no-unused-vars”:”off”
javascript;gutter:true;
{
"name": "music_player",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.27.2",
"core-js": "^3.8.3",
"qs": "^6.11.0",
"vant": "^2.12.48",
"vue": "^2.6.14",
"vue-router": "^3.5.2"
},
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3",
"vue-template-compiler": "^2.6.14"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "@babel/eslint-parser"
},
"rules": {
"no-unused-vars": "off"
}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}</p>
<pre><code>
## 编写登录页面
### 调整页面整体样式
;gutter:true;
export default {
}
/* 调整页面样式 */
/* 设置页面的整体样式 */
.login {
width: 100%;
height: 100vh;
/* 调整渐变色 */
background-image: linear-gradient(#70e1f5, #e5e5be, #e4e5e6);
overflow: hidden;
}
好看的渐变色获取网站https://uigradients.com/#Sylvia
App的名称或主题图片
往class=”login”的div里添加代码
javascript;gutter:true;
XX音乐</p>
<pre><code>
设置头部区域的样式
;gutter:true;
/* 设置头部区域的样式 */
.header {
width: 100%;
/* 声明为绝对定位布局 */
position: absolute;
top: 60px;
text-align: center;
}
.header .title h1 {
color: #8a8a8a;
display: inline;
vertical-align: top;
}
.header .title img {
width: 45px;
}
获取矢量图标的网站https://www.iconfont.cn/
在src下新建文件夹img,下载所需要的图标
在空出的图片img的src中填入图片路径../img/ttleMusic.png
html;gutter:true;
XX音乐</p>
<p>export default {};</p>
<p>/<em> 调整页面样式 </em>/
/<em> 设置页面的整体样式 </em>/
.login {
width: 100%;
height: 100vh;
/<em> 调整渐变色 </em>/
background-image: linear-gradient(#70e1f5, #e5e5be, #e4e5e6);
overflow: hidden;
}
/<em> 设置头部区域的样式 </em>/
.header {
width: 100%;
/<em> 声明为绝对定位布局 </em>/
position: absolute;
top: 60px;
text-align: center;
}
.header .title h1 {
color: #8a8a8a;
display: inline;
vertical-align: top;
}
.header .title img {
width: 45px;
}</p>
<pre><code>
### 大logo
继续在class="login"的div里写入代码
;gutter:true;
听我想听
设置样式
html;gutter:true;
/<em> 设置主题中心区域的样式 </em>/
.logo {
width: 100%;
/<em> 声明为绝对定位布局 </em>/
position: absolute;
top: 60px;
text-align: center;
top: 150px;
color: #1afa29;
}
.logo p {
font-size: 30px;
font-family: "Times New Roman", Times, serif;
}</p>
<pre><code>
### 登录表单的区域
;gutter:true;
提交
设置样式
html;gutter:true;
/<em> 设置登录表单区域的样式 </em>/
.loginArea {
width: 90%;
/<em> 通过外边距的形式 </em>/
margin: 460px auto;
/<em> 设置圆角 </em>/
border-radius: 15px;
}
.loginArea .van-form .van-cell {
/<em> 设置圆角 </em>/
border-radius: 15px;
/<em> 设置背景色通明 </em>/
background-color: rgba(255, 255, 255, 0.2);
height: 50px;
}
.loginArea .van-form .van-button {
background-image: linear-gradient(to right, #74ebd5, #acb6e5);
}</p>
<pre><code>
编写js代码
;gutter:true;
export default {
data() {
return {
// 用户名
username: "",
// 密码
password: "",
};
},
methods: {
// 登录事件
onSubmit() {
// 设置对应的参数
let userInfo = {
// 用户名
username: this.username,
// 密码
password: this.password,
};
console.log(userInfo);
sessionStorage.setItem(‘userInfo’,userInfo.username)
this.$router.push("/manage/home");
},
},
};
路由管理页面
在src/views/Manage.vue文件中写入代码
html;gutter:true;
首页</p>
<pre><code> 我的
</code></pre>
<p>export default {
data() {
return {
active: 0,
};
},
};</p>
<pre><code>
## 自定义播放器组件
在src/components目录下新建文件MusicPlayer.vue
;gutter:true;
{{ songName }}
export default {
props: {
songList: [],
},
data() {
return {
//songList: [
// {
// songId: "5257138", //512085302
// songName: "屋顶",
// songImg:
// "https://p1.music.126.net/81BsxxhomJ4aJZYvEbyPkw==/109951165671182684.jpg",
// songUrl: "https://music.163.com/song/media/outer/url?id=5257138.mp3",
// },
//],
songId: "",
songName: "",
songImg: "",
songUrl: "",
songIndex: 0,
};
},
// 自动调用
created() {
this.reload();
},
methods: {
// 更新播放歌曲
reload() {
// console.log(this.songIndex + 1 + " in " + this.songList.length+’:’+this.songList[this.songIndex].songUrl);
this.songId = this.songList[this.songIndex].songId;
this.songImg = this.songList[this.songIndex].songImg;
this.songName = this.songList[this.songIndex].songName;
this.songUrl = this.songList[this.songIndex].songUrl;
},
// 播放歌曲
playSong() {
let audio = this.$el.querySelector("#audio");
let musicContainer = this.$el.querySelector("#music-container");
let playBtn = this.$el.querySelector("#play");
musicContainer.classList.add("play");
playBtn.querySelector("i.fas").classList.remove("fa-play");
playBtn.querySelector("i.fas").classList.add("fa-pause");
audio.play();
},
// 播放器按钮
playBtn() {
let musicContainer = this.$el.querySelector("#music-container");
musicContainer.classList.contains("play")
? this.pauseSong()
: this.playSong();
},
// 停止播放
pauseSong() {
let audio = this.$el.querySelector("#audio");
let musicContainer = this.$el.querySelector("#music-container");
let playBtn = this.$el.querySelector("#play");
musicContainer.classList.remove("play");
playBtn.querySelector("i.fas").classList.add("fa-play");
playBtn.querySelector("i.fas").classList.remove("fa-pause");
audio.pause();
},
// 上一首
prevSong() {
this.songIndex–;
if (this.songIndex < 0) {
this.songIndex = this.songList.length – 1;
}
// 加载歌曲信息并播放
this.reload();
this.pauseSong();
},
// 下一首
nextSong() {
this.songIndex++;
if (this.songIndex > this.songList.length – 1) {
this.songIndex = 0;
}
this.reload();
this.pauseSong();
return this.songIndex;
},
// 结束
},
mounted() {
const audio = document.getElementById("audio");
const progress = document.getElementById("progress");
const progressContainer = document.getElementById("progress-container");
// 进度条更新
function updateProgress(e) {
// 对象解构操作
const { duration, currentTime } = e.target;
const progressPercent = (currentTime / duration) * 100;
// 进度条
progress.style.width = ${progressPercent}%
;
}
// 设置进度条
function setProgress(e) {
// progressContainer代理视图宽度
const width = this.clientWidth;
// 鼠标点击时处于progressContainer里的水平偏移量
const clickX = e.offsetX;
// audio.duration: 音频长度
const duration = audio.duration;
// audio.currentTime: 音频播放位置
audio.currentTime = (clickX / width) * duration;
}
// 事件监听
// 3.播放器进度条相关
// 3.1 设置播放进度
progressContainer.onclick = setProgress;
// 3.2 进度条更新
audio.ontimeupdate = updateProgress;
},
};
@import "../../public/style.css";
@import "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css";
在public目录下新建文件style.css
css;gutter:true;
@import url('https://fonts.googleapis.com/css?family=Lato&display=swap');</p>
<p>.music-container {
background-image: linear-gradient(#ff6e7f, #bfe9ff);
border-radius: 15px;
display: flex;
position: fixed;
margin: 0;
left: 50%;
transform: translate(-50%,0);
z-index: 5;
}</p>
<p>.img-container {
position: relative;
width: 110px;
}</p>
<p>.img-container::after {
content: "";
background-color: #fff;
border-radius: 50%;
position: absolute;
bottom: 100%;
left: 50%;
width: 15px;
height: 15px;
/<em> 旋转 </em>/
transform: translate(-50%, 50%);
}</p>
<p>.img-container img {
border-radius: 50%;
height: 110px;
width: inherit;
object-fit: cover;
position: absolute;
bottom: 0;
left: 0;
/<em> 封面360°旋转,默认不动 </em>/
animation: rotate 3s linear infinite;
animation-play-state: paused;
}</p>
<p>/<em> 定义旋转动画 </em>/
@keyframes rotate {
from {
transform: rotate(0);
}</p>
<pre><code>to {
transform: rotate(360deg);
}
</code></pre>
<p>}</p>
<p>.navigation {
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
}</p>
<p>.action-btn {
/<em> 取消默认样式 </em>/
border: 0;
background-color: rgba(247, 247, 247, 0.1);
/<em> ----- </em>/
color:#ff6e7f;
font-size: 20px;
cursor: pointer;
padding: 10px;
margin: 0 20px;
}</p>
<p>.action-btn:focus {
/<em> 取消默认样式 </em>/
outline: 0;
}</p>
<p>.action-btn.action-btn-big {
font-size: 30px;
}</p>
<p>.music-info {
position: absolute;
top: 0;
left: 20px;
/<em> 父元素宽度-40px </em>/
width: calc(100% - 200px);
background-color: rgba(255, 255, 255, 0.5);
border-radius: 15px 15px 0 0;
padding: 10px 10px 10px 150px;
/<em> 没播放时默认隐藏 </em>/
opacity: 0;
transform: translateY(0%);
transition: transform 0.3s ease-in, opacity 0.3s ease-in;
z-index: 0;
}</p>
<p>.music-info h4 {
/<em> 取消默认边距 </em>/
margin: 0;
}</p>
<p>.music-container.play .music-info {
opacity: 1;
transform: translateY(-100%);
}</p>
<p>.progress-container {
background-color: #fff;
border-radius: 5px;
cursor: pointer;
margin: 10px 0;
height: 4px;
width: 100%;
}</p>
<p>.progress {
background-color: #0decfc;
border-radius: 5px;
height: 100%;
/<em> 一开始进度条长度为0 </em>/
width: 0%;
transition: width 0.1s linear;</p>
<p>}</p>
<pre><code>
## 编写主页
;gutter:true;
{{ item.name }}
推荐歌曲
import MusicPlayer from "../../components/MusicPlayer.vue";
import { get } from "../../http/axios";
export default {
data() {
return {
// 轮播图
swiperPic: [],
// 宫格
songGrid: [],
// 歌曲列表
songList: [],
show: false,
};
},
components: { MusicPlayer },
created() {
this.getSongListData();
this.getSwiperData();
this.getSongGridData();
this.addSong();
},
methods: {
addSong() {
// 获取到路由传参传递过来的activeKey 给data中的对应的变量进行赋值
// console.log(this.$route.query.songId);
if (this.$route.query.songId)
this.songList.push({
songId: this.$route.query.songId,
songName: this.$route.query.songName,
songImg: this.$route.query.songImg,
songUrl: this.$route.query.songUrl,
});
},
// 点击事件播放歌曲
playSong(index) {
// console.log(index);
for (; this.$refs.playSong.nextSong() != index; ) {}
},
// 获取歌曲列表数据
async getSongListData() {
// 发送网络请求
let res = await get("/personalized/newsong");
// console.log(res.data.result);
// 向data中的变量进行赋值
for (let index in res.data.result) {
if (index < 10)
this.songList.push({
songId: res.data.result[index].id,
songName: res.data.result[index].name,
songImg: res.data.result[index].picUrl,
songUrl:
"https://music.163.com/song/media/outer/url?id=" +
res.data.result[index].id +
".mp3",
});
}
this.show = true;
},
// 获取轮播图数据
async getSwiperData() {
// 1.发送网络请求 获取对应的数据
let res = await get("/homepage/block/page");
this.swiperPic = res.data.data.blocks[0].extInfo.banners;
},
// 获取宫格数据
async getSongGridData() {
// 发送网络请求获取对应的数据
let res = await get("/homepage/dragon/ball");
// console.log(res.data.data);
// 向data中的变量进行赋值
this.songGrid = res.data.data;
},
// 点击搜索框跳转到关于页面
gotoAboutPage() {
this.$router.push("/manage/about");
},
/**
*
*/
},
};
/* 整体样式 */
.home {
background-image: linear-gradient(to right, #ff6e7f, #bfe9ff);
}
/* 分区样式 */
.swiper,
.songList,
.songGrid {
margin: 15px;
}
.my-swipe,
.songList .goodList {
border-radius: 15px;
}
/* 轮播图样式 */
.my-swipe {
height: 120px;
}
.my-swipe .van-swipe-item {
color: #fff;
font-size: 20px;
line-height: 150px;
text-align: center;
background-color: #39a9ed;
}
/* 歌单宫格样式 */
.songGrid {
/* height: 110px; */
padding: 5px;
background-color: rgba(247, 247, 247, 0.4);
border-radius: 15px;
}
.songGrid /deep/ .van-grid-item__content {
background-color: rgba(255, 255, 255, 0);
}
/* 歌单样式 */
.songList .goodList .goods-card,
.songList .text {
margin: 0;
padding: 10px;
background-color: rgba(247, 247, 247, 0.4);
}
.songList .goodList .text {
font-size: 30px;
font-family: Cambria, Cochin, Georgia, Times, "Times New Roman", serif;
}
.songList .goodList .goods-card .van-card__header {
height: 60px;
}
.songList .goodList .goods-card .van-card__title {
font-size: 20px;
height: 30px;
}
.songList .goodList .goods-card .van-card__thumb {
width: 60px;
height: 60px;
}
.songList .goodList .goods-card .delete-button {
height: 100%;
}
/* 音乐播放器 */
.musicArea {
width: 100%;
height: 100px;
position: fixed;
bottom: 0px;
}
编写我的页面
html;gutter:true;
{{ userInfo.username }}</p>
<pre><code>退出登录
</code></pre>
<p>import { Dialog } from "vant";
export default {
data() {
return {
// 用户信息
userInfo:{
username:"马保国"
}
};
},
created() {
this.getUserInfo()
},
methods: {
getUserInfo(){
this.userInfo.username=sessionStorage.getItem('userInfo')
},
// 退出登录
logoutHandler() {
// 做一个提示
Dialog.confirm({
message: "是否确认退出登录?",
theme: "round-button",
})
.then(() => {
// 点击确认按钮 执行退出登录
// 清除掉本地保存的token 执行退出的网络操作
// delToken();
// 跳转回到登录页面
this.$router.push("/login");
})
.catch(() => {
// on cancel
});
},
},
};</p>
<p>/<em> 设置顶部的背景样式 </em>/
.mine .bg {
/<em> 设置渐变色 </em>/
background-image: linear-gradient(to right, #ff6e7f, #bfe9ff);
height: 200px;
/<em> 设置底部左右两侧的弧度为一个圆形 </em>/
border-bottom-left-radius: 50%;
border-bottom-right-radius: 50%;
}
/<em> 用户区域样式 </em>/
.mine .userInfo {
background-color: #fff;
width: 80%;
height: 160px;
/<em> 开启绝对定位 </em>/
position: absolute;
top: 100px;
left: 50%;
margin-left: -40%;
/<em> 透明度 </em>/
opacity: 0.8;
/<em> 阴影 </em>/
box-shadow: 0 0 10px #ccc;
border-radius: 10px;
}
/<em> 用户区域头像样式 </em>/
.userInfo .userFace {
width: 100px;
height: 100px;
/<em> 要设置一个元素为圆形 </em>/
border-radius: 50%;
/<em> margin: 0 auto; </em>/
position: absolute;
left: 50%;
/<em> 形变 平移 </em>/
transform: translate(-50%, -50%);
}
/<em> 用户区域头像的图片样式 </em>/
.userInfo .userFace img {
width: 100%;
height: 100%;
border-radius: 50%;
}
/<em> 用户名的样式 </em>/
.userInfo .userName {
/<em> background-color: green; </em>/
text-align: center;
margin-top: 70px;
font-size: 28px;
}
/<em> 设置操作列表区域的样式 </em>/
.mine .cellArea {
margin: 120px auto;
width: 95%;
box-shadow: 4px 4px 4px 0 rgba(248, 123, 140, 0.3);
border-radius: 10px;
}
/<em> van-cell的样式 </em>/
.search-icon {
font-size: 16px;
line-height: inherit;
}
/<em> 退出按钮的样式 </em>/
.logoutBtn {
width: 50%;
/<em> 设置渐变色 </em>/
background-image: linear-gradient(to right, #ff6e7f, #bfe9ff);
text-align: center;
color: #fff;
/<em> 设置行高 </em>/
line-height: 35px;
border-radius: 20px;
margin: 0 auto;
cursor: pointer;
}</p>
<pre><code>
## 编写搜索页面
;gutter:true;
单曲
import { get } from "../../http/axios";
export default {
data() {
return {
value: "",
songList: [],
showList: false,
};
},
methods: {
// 取消并返回
onCancel() {
this.$router.go(-1);
},
// 通过搜索获取歌曲
async getSearchData() {
this.songList = [];
this.showList = false;
let data = {
keywords: this.value,
};
let res = await get("/search", data);
this.songList = [];
for (let index in res.data.result.songs) {
this.getSongDetailById(res.data.result.songs[index].id);
}
// });
},
// 通过歌曲id获取歌曲详情
async getSongDetailById(Id) {
let data = {
ids: Id,
};
let res = await get("/song/detail", data);
this.songList.push({
songId: res.data.songs[0].id,
songName: res.data.songs[0].name,
songDesc: res.data.songs[0].ar[0].name,
songImg: res.data.songs[0].al.picUrl,
songUrl:
"https://music.163.com/song/media/outer/url?id=" +
res.data.songs[0].id +
".mp3",
});
this.showList = true;
// });
},
// 播放歌曲并跳转
playSong(index) {
// 跳转页面 并 传参
this.$router.push({
// 页面的路径
path: "/manage/home",
// 传递的参数
query: {
songId: this.songList[index].songId,
songName: this.songList[index].songName,
songImg: this.songList[index].songImg,
songUrl: this.songList[index].songUrl,
},
});
},
},
};
/* 整体样式 */
.about {
background-image: linear-gradient(to right, #ff6e7f, #bfe9ff);
}
/* 歌单样式 */
.songList {
margin: 15px;
}
.songList .goodList {
border-radius: 15px;
}
.songList .goodList .goods-card,
.songList .text {
margin: 0;
padding: 10px;
background-color: rgba(247, 247, 247, 0.4);
}
.songList .goodList .text {
font-size: 30px;
font-family: Cambria, Cochin, Georgia, Times, "Times New Roman", serif;
}
.songList .goodList .goods-card .van-card__header {
height: 60px;
}
.songList .goodList .goods-card .van-card__title {
padding: 2px 0;
font-size: 20px;
height: 30px;
}
.songList .goodList .goods-card .delete-button {
height: 100%;
}
/* 未输入 */
.songList .noInput .van-empty {
height: 650px;
}
Original: https://www.cnblogs.com/linlinmailbox/p/16471454.html
Author: 霖霖的信箱
Title: vue+vant音乐播放器(andriod)项目
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/607104/
转载文章受原作者版权保护。转载请注明原作者出处!