vue+vant音乐播放器(andriod)项目
新建项目
在适合的目录下打开终端输入vue create music_player,回车
选择Default([Vue 2] babel,eslint)
等待项目构建完成
项目构建成功
安装路由
用vscode打开项目所在文件夹
新建终端输入命令npm install vue-router@3.5.2 --save
在src目录下新建文件夹router,并在其下新建文件index.js
在新建的文件index.js中写入路由模板代码,成为路由配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) const routes = [] const router = new VueRouter({ mode: 'history' , base: process.env.BASE_URL, routes }) export default router |
在main.js中引入路由配置文件
1 2 3 4 5 6 7 8 9 10 11 | 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文件中清除多余代码,并写入全局路由组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <template> <div> <!-- 全局组件 --> <router-view></router-view> </div> </template> <script> export default { } </script> <style scoped> /* 全局设置样式 */ html,body, #app{ height: 100%; } </style> |
安装vant组件库
在终端中输入npm install vant@latest-v2 -S
在终端中输入npm install qs --save
在src目录下新建文件夹plugins,并在其下新建文件vant.js
并写入代码
1 2 3 4 5 | import Vue from 'vue' import Vant, { Locale } from 'vant' import 'vant/lib/index.css' Vue.use(Vant) |
在main.js中引入vant.js
1 2 3 4 5 6 7 8 9 10 11 12 13 | import Vue from 'vue' import App from './App.vue' //引入路由 import router from './router' //引入vant.js文件 import './plugins/vant.js' Vue.config.productionTip = false new Vue({ router, render: h => h(App), }).$mount( '#app' ) |
安装axios
在终端中输入npm install axios --save
在src目录下新建文件夹http,并新建文件axios.js
并写入代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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中写入代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) 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' ) } ] } ] const router = new VueRouter({ // mode: 'history', base: process.env.BASE_URL, routes }) export default router |
一些问题的解决方案
在 vue eslint 报错 error “Component name “*****“ should always be multi-word”
在vue.config.js文件中加入代码lintOnSave:false
1 2 3 4 5 | 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"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | { "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" ] } |
编写登录页面
调整页面整体样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <template> <div class = "login" > </div> </template> <script> export default { } </script> <style scoped> /* 调整页面样式 */ /* 设置页面的整体样式 */ .login { width: 100%; height: 100vh; /* 调整渐变色 */ background-image: linear-gradient( #70e1f5, #e5e5be, #e4e5e6); overflow: hidden; } </style> |
好看的渐变色获取网站https://uigradients.com/#Sylvia
App的名称或主题图片
往class="login"的div里添加代码
1 2 3 4 5 6 7 8 9 10 | <div class = "login" > <!-- 登录页面的头部 --> <div class = "header" > <!-- App的名称或主题图片 --> <div class = "title" > <img src= "" alt= "" /> <h1>XX音乐</h1> </div> </div> </div> |
设置头部区域的样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* 设置头部区域的样式 */ .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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | < template > < div class="login"> <!-- 登录页面的头部 --> < div class="header"> <!-- App的名称或主题图片 --> < div class="title"> < img src="../img/titleMusic.png" alt="图片加载失败" /> < h1 >XX音乐</ h1 > </ div > </ div > </ div > </ template > < script > export default {}; </ script > < style scoped> /* 调整页面样式 */ /* 设置页面的整体样式 */ .login { width: 100%; height: 100vh; /* 调整渐变色 */ background-image: linear-gradient(#70e1f5, #e5e5be, #e4e5e6); overflow: hidden; } /* 设置头部区域的样式 */ .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; } </ style > |
大logo
继续在class="login"的div里写入代码
1 2 3 4 5 | <!-- 大logo --> < div class="logo"> < img src="../img/themeMusic.png" alt="图片加载失败" /> < p >听我想听</ p > </ div > |
设置样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* 设置主题中心区域的样式 */ .logo { width: 100%; /* 声明为绝对定位布局 */ position: absolute; top: 60px; text-align: center; top: 150px; color: #1afa29; } .logo p { font-size: 30px; font-family: "Times New Roman", Times, serif; } |
登录表单的区域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <!-- 登录表单的区域 --> < div class="loginArea"> < van-form @submit="onSubmit"> < van-field v-model="username" name="用户名" label="用户名" placeholder="用户名" :rules="[{ required: true, message: '请填写用户名' }]" /> < van-field v-model="password" type="password" name="密码" label="密码" placeholder="密码" :rules="[{ required: true, message: '请填写密码' }]" /> < div style="margin: 16px"> < van-button round block type="info" native-type="submit" >提交</ van-button > </ div > </ van-form > </ div > |
设置样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /* 设置登录表单区域的样式 */ .loginArea { width: 90%; /* 通过外边距的形式 */ margin: 460px auto; /* 设置圆角 */ border-radius: 15px; } .loginArea .van-form .van-cell { /* 设置圆角 */ border-radius: 15px; /* 设置背景色通明 */ background-color: rgba(255, 255, 255, 0.2); height: 50px; } .loginArea .van-form .van-button { background-image: linear-gradient(to right, #74ebd5, #acb6e5); } |
编写js代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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文件中写入代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | < template > < div class="manage"> <!-- 声明渲染组件routerView --> < router-view ></ router-view > <!-- 创建tabbar结构 --> < van-tabbar v-model="active"> <!-- 首页 --> < van-tabbar-item icon="home-o" to="/manage/home">首页</ van-tabbar-item > <!-- 我的 --> < van-tabbar-item icon="friends-o" to="/manage/me">我的</ van-tabbar-item > </ van-tabbar > </ div > </ template > < script > export default { data() { return { active: 0, }; }, }; </ script > < style scoped> </ style > |
自定义播放器组件
在src/components目录下新建文件MusicPlayer.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | < template > < div > < div class="music-container" id="music-container"> <!-- 音乐信息 --> < div class="music-info"> <!-- 音乐标题 --> < h4 id="title">{{ songName }}</ h4 > <!-- 音乐播放进度条 --> < div class="progress-container" id="progress-container"> < div class="progress" id="progress"></ div > </ div > </ div > <!-- 默认第一首音乐 --> < audio :src="songUrl" id="audio"></ audio > <!-- 音乐封面 --> < div class="img-container"> < img :src="songImg" alt="加载中" id="music-cover" /> </ div > <!-- 播放控制 --> < div class="navigation"> < button id="prev" class="action-btn" @click="prevSong"> < i class="fas fa-backward"></ i > </ button > < button id="play" class="action-btn action-btn-big" @click="playBtn"> < i class="fas fa-play"></ i > </ button > < button id="next" class="action-btn" @click="nextSong"> < i class="fas fa-forward"></ i > </ button > </ div > </ div > </ div > </ template > < script > 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; }, }; </ script > < style scoped> @import "../../public/style.css"; @import "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css"; </ style > |
在public目录下新建文件style.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | @import url ( 'https://fonts.googleapis.com/css?family=Lato&display=swap' ); .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 ; } .img-container { position : relative ; width : 110px ; } .img-container::after { content : "" ; background-color : #fff ; border-radius: 50% ; position : absolute ; bottom : 100% ; left : 50% ; width : 15px ; height : 15px ; /* 旋转 */ transform: translate( -50% , 50% ); } .img-container img { border-radius: 50% ; height : 110px ; width : inherit; object-fit: cover; position : absolute ; bottom : 0 ; left : 0 ; /* 封面360°旋转,默认不动 */ animation: rotate 3 s linear infinite; animation-play-state: paused; } /* 定义旋转动画 */ @keyframes rotate { from { transform: rotate( 0 ); } to { transform: rotate( 360 deg); } } .navigation { display : flex; align-items: center ; justify- content : center ; z-index : 1 ; } .action-btn { /* 取消默认样式 */ border : 0 ; background-color : rgba( 247 , 247 , 247 , 0.1 ); /* ----- */ color : #ff6e7f ; font-size : 20px ; cursor : pointer ; padding : 10px ; margin : 0 20px ; } .action-btn:focus { /* 取消默认样式 */ outline : 0 ; } .action-btn.action-btn-big { font-size : 30px ; } .music-info { position : absolute ; top : 0 ; left : 20px ; /* 父元素宽度-40px */ width : calc( 100% - 200px ); background-color : rgba( 255 , 255 , 255 , 0.5 ); border-radius: 15px 15px 0 0 ; padding : 10px 10px 10px 150px ; /* 没播放时默认隐藏 */ opacity: 0 ; transform: translateY( 0% ); transition: transform 0.3 s ease-in, opacity 0.3 s ease-in; z-index : 0 ; } .music-info h 4 { /* 取消默认边距 */ margin : 0 ; } .music-container.play .music-info { opacity: 1 ; transform: translateY( -100% ); } .progress-container { background-color : #fff ; border-radius: 5px ; cursor : pointer ; margin : 10px 0 ; height : 4px ; width : 100% ; } .progress { background-color : #0decfc ; border-radius: 5px ; height : 100% ; /* 一开始进度条长度为0 */ width : 0% ; transition: width 0.1 s linear; } |
编写主页
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | < template > < div class="home"> <!-- 搜索框 --> < van-sticky > < div class="search"> < van-search shape="round" background="linear-gradient(to right,#ff6e7f, #bfe9ff)" placeholder="请输入搜索关键词" @click="gotoAboutPage" /> </ div > </ van-sticky > <!-- 轮播图 --> < div class="swiper"> < van-swipe class="my-swipe" :autoplay="1500" indicator-color="white" :height="200" > < van-swipe-item v-for="(item, index) in swiperPic" :key="index"> < img :src="item.pic" alt="无法加载图片" width="100%" :v-lazy="item.pic" /> </ van-swipe-item > </ van-swipe > </ div > <!-- 歌单宫格 --> < div class="songGrid"> < van-grid :border="true" :column-num="5" square> < van-grid-item v-for="(item, index) in songGrid" :key="index"> < van-image :src="item.iconUrl" style=" width: 30px; background-image: linear-gradient(#ed4264, #ffedbc); border-radius: 50px; " /> < div style="font-size: 10px; height: 0px">{{ item.name }}</ div > </ van-grid-item > </ van-grid > </ div > <!-- 歌单 --> < div class="songList"> < van-swipe-cell class="goodList" v-if="show"> < div class="text">推荐歌曲</ div > < van-card v-for="(item, index) in songList" :key="index" :title="item.songName" :v-lazy="item.songImg" :thumb="item.songImg" class="goods-card" @click="playSong(index)" /> </ van-swipe-cell > <!-- 未加载 --> < div class="noLoad" v-else> < van-empty image="network" description="网络错误" /> </ div > < div class="space"> < van-card style="background-color: rgba(247, 247, 247, 0)" /> </ div > < div class="space"> < van-card style="background-color: rgba(247, 247, 247, 0)" /> </ div > </ div > <!-- 音频播放器 --> < div class="musicArea"> < MusicPlayer :songList="songList" v-if="show" ref="playSong" class="music-player" ></ MusicPlayer > </ div > </ div > </ template > < script > 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"); }, /** * */ }, }; </script> < style scoped> /* 整体样式 */ .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; } </ style > |
编写我的页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | < template > < div class="mine"> <!-- 顶部的背景 --> < div class="bg"></ div > <!-- 顶部用户信息 --> < div class="userInfo"> <!-- 用户头像 --> < div class="userFace"> < img src="../../img/head.jpg" alt="" /> </ div > <!-- 用户名 --> < div class="userName"> {{ userInfo.username }} </ div > </ div > <!-- 操作列表 指示列表 --> < div class="cellArea"> <!-- title 标题 icon-是左侧图标 name-右侧图标 --> < van-cell title="设置" icon="setting-o"> <!-- 使用 right-icon 插槽来自定义右侧图标 --> < template #right-icon> < van-icon name="arrow" class="search-icon" /> </ template > </ van-cell > < van-cell title="联系我们" icon="service-o"> <!-- 使用 right-icon 插槽来自定义右侧图标 --> < template #right-icon> < van-icon name="arrow" class="search-icon" /> </ template > </ van-cell > < van-cell title="关于我们" icon="service-o"> <!-- 使用 right-icon 插槽来自定义右侧图标 --> < template #right-icon> < van-icon name="arrow" class="search-icon" /> </ template > </ van-cell > </ div > <!-- 退出按钮 --> < div class="logoutBtn" @click="logoutHandler">退出登录</ div > </ div > </ template > < script > 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 }); }, }, }; </ script > < style scoped> /* 设置顶部的背景样式 */ .mine .bg { /* 设置渐变色 */ background-image: linear-gradient(to right, #ff6e7f, #bfe9ff); height: 200px; /* 设置底部左右两侧的弧度为一个圆形 */ border-bottom-left-radius: 50%; border-bottom-right-radius: 50%; } /* 用户区域样式 */ .mine .userInfo { background-color: #fff; width: 80%; height: 160px; /* 开启绝对定位 */ position: absolute; top: 100px; left: 50%; margin-left: -40%; /* 透明度 */ opacity: 0.8; /* 阴影 */ box-shadow: 0 0 10px #ccc; border-radius: 10px; } /* 用户区域头像样式 */ .userInfo .userFace { width: 100px; height: 100px; /* 要设置一个元素为圆形 */ border-radius: 50%; /* margin: 0 auto; */ position: absolute; left: 50%; /* 形变 平移 */ transform: translate(-50%, -50%); } /* 用户区域头像的图片样式 */ .userInfo .userFace img { width: 100%; height: 100%; border-radius: 50%; } /* 用户名的样式 */ .userInfo .userName { /* background-color: green; */ text-align: center; margin-top: 70px; font-size: 28px; } /* 设置操作列表区域的样式 */ .mine .cellArea { margin: 120px auto; width: 95%; box-shadow: 4px 4px 4px 0 rgba(248, 123, 140, 0.3); border-radius: 10px; } /* van-cell的样式 */ .search-icon { font-size: 16px; line-height: inherit; } /* 退出按钮的样式 */ .logoutBtn { width: 50%; /* 设置渐变色 */ background-image: linear-gradient(to right, #ff6e7f, #bfe9ff); text-align: center; color: #fff; /* 设置行高 */ line-height: 35px; border-radius: 20px; margin: 0 auto; cursor: pointer; } </ style > |
编写搜索页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | < template > < div class="about"> <!-- 搜索框 --> < van-sticky > < div class="search"> < van-search shape="round" background="linear-gradient(to right,#ff6e7f, #bfe9ff)" v-model="value" clearable placeholder="请输入搜索关键词" @input="getSearchData" > < template #left-icon> < van-icon name="arrow-left" @click="onCancel"/> </ template > </ van-search > </ div > </ van-sticky > <!-- 歌单 --> < div class="songList"> <!-- 已输入 --> < div class="input" v-if="showList"> < van-swipe-cell class="goodList"> < div class="text">单曲</ div > < van-card v-for="(item, index) in songList" :key="index" :title="item.songName" :desc="item.songDesc" class="goods-card" @click="playSong(index)" /> </ van-swipe-cell > </ div > <!-- 未输入 --> < div class="noInput" v-else> < van-empty image="search" /> </ div > < div class="space"> < van-card style="background-color: rgba(247, 247, 247, 0)" /> </ div > </ div > </ div > </ template > < script > 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, }, }); }, }, }; </ script > < style scoped> /* 整体样式 */ .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; } </ style > |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!