# vue-music **Repository Path**: bolsters/vue-music ## Basic Information - **Project Name**: vue-music - **Description**: vue-music 待完成 。github[完成项目]: https://github.com/aLittleLittleStar/Vue-Music-App - **Primary Language**: JavaScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 30 - **Forks**: 12 - **Created**: 2018-09-26 - **Last Updated**: 2025-08-31 ## Categories & Tags **Categories**: multimedia **Tags**: None ## README # vue-music > A Vue.js project ## Build Setup ``` bash # install dependencies npm install # serve with hot reload at localhost:8080 npm run dev # build for production with minification npm run build # build for production and view the bundle analyzer report npm run build --report ``` For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). #### 分支说明 master 主分支 包含全部代码 base-framework 基础组件制作 recommend 推荐页面制作 singer 歌手列表页面制作 singer-detail 歌手详情页面制作分支 player-kernel 播放器内核组件制作 [TOC] ## 项目准备工作 [第二章] ### 需求分析[2-1] ### vue-cli脚手架安装[2-2] > > npm install vue-cli --save > ### 项目目录、图标字体、公共样式等资源准备 [2-3] #### 修改目录 + 删除src目录下的原目录 改为 + src + api + 放置后端请求相关的代码 [ajax、jsonp]请求 + common => 通用的静态资源 + fonts + image + js + stylus => 通用的样式文件 + components + 通用组件 + router + 路由 + store + 存放vuex相关的代码 #### 安装stylus-loader、stylus、babel-runtime、fastclick、babel-polyfill > 安装stylus 支持__stylus__语法 > > npm install stylus --save > > npm install stylus-loader --save > > babel-runtime 转译es6语法 > > fastclick 解决移动端点击300ms延迟的问题 > > 在main.js > ``` import fastclick from 'fastclick' fastclick.attach(document.body) ``` > babel-polyfill 补丁,对es6一些api的转译 > ## 页面基础骨架搭建 [第三章] > > 项目入口文件m-header.vue的编写 > > 添加rank、recommend、search、singer、tab等页面 > > 在router文件夹里面的index.js里面设置路由 > > 在App.vue文件里面引入tab.vue > > 在tab.vue里面设置顶部导航跳转 > > ## 推荐页面制作 recommend.vue[第四章] ### 动态获取QQ音乐里面的数据 jsonp ### JSONP原理 + 封装[4-2] > [github地址](https://github.com/webmodules/jsonp) > > 安装 > > npm install jsonp --save > > 使用jsonp > > common/js/jsonp.js > ### JSONP的应用 + 轮播图数据的抓取 [4-3] ``` src/common/js/jsonp.js src/api/config src/api/recommend.js ``` ### 轮播图组件的实现[4-4]-[4-6] > 新建src/base基础组件库 > > slider.vue > > slot 插槽 > > 安装better-scroll > > 浏览器视口发生改变时轮播图大小要发生改变 > ``` // 当视口宽度改变时轮播图大小进行改变 window.addEventListener('resize', () => { if (!this.slider) { return } this._setSliderWidth(true) this.slider.refresh() }) <<<<<<< HEAD }, ``` ### 歌单数据分析[4-7] __APP.vue__ ``` ``` #### 抓取QQ音乐PC端的推荐歌单数据 __500: 服务端错误__ > > 没有办法直接调用QQ音乐的api地址 > > __解决办法__ > > 使用后端代理 > __webpack.dev.config.js__ ``` // 后端代理 const express = require('express') const axios = require('axios') const app = express() const apiRoutes = express.Router() app.use('/api', apiRoutes) ``` > > 安装 axios > > npm install axios --save > 用axios 进行代理 ``` before(app){ // 使用axios 进行代理 // 歌单列表数据 app.get('/api/getDiscList', function (req, res) { let url = 'https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg' axios.get(url, { headers: { referer: 'https://c.y.qq.com/', host: 'c.y.qq.com' }, // 参数 params: req.query }).then((response) => { res.json(response.data) }).catch((e) => { console.log(e.response) }) }) }, ``` ### 歌单列表组件开发和数据应用[4-9] ```

``` v-html="item.creator.name" 进行转译字符 ### SCROLL组件的抽象和应用[4-10]-[4-11] #### 创建scroll.vue组件 ### lazyload懒加载插件的安装和使用[4-12] __安装:__ npm install vue-lazyload --save __使用:__ 在main.js里面引入 import VueLazyLoad from 'vue-lazyload' ``` Vue.use(VueLazyLoad, { loading: require('@/common/image/default.png') }) ``` > 在recommend.vue > ``` ``` ### loading基础组件的开发和应用[4-13] ## 歌手页面开发[第五章] ## 歌手详情页面[第六章] ### singer-detail.vue [6-2] ### Vuex [6-3] ### Vuex 初始化及歌手数据配置[6-4] > > 文件地址 src/store > + + store + index.js // 入口文件 + actions.js // 异步 操作/ 修改 封装 + getters.js // 映射 + mutation-types.js // mutations 相关的字符串常量 + mutations.js // + state.js // 管理 状态 #### 安装 vuex npm install vuex --save > > store/index.js > // 修改 state 时 在控制台打印 logger 日志,方便查看修改了什么 > > `import createLogger from 'vuex/dist/logger'` > > __注册store__ 在 msin.js 里面 `import store from './store'` > ``` new Vue({ el: '#app', router, store, render: h => h(App) }) ``` ### music-list.vue 组件 [6-8] - [6-14] > > > singer-detail.vue 与 music-list.vue 组件 之间的数据传递 [父组件<=>子组件] ### song-list.vue [6-9] > > > 新建 @/base/song-list/song-list.vue 基础组件 > > 歌单列表。通过for循环遍历出数据 > ### music-list.vue 组件 实现列表下拉 图片放大 [6-12] ``` let scale = 1 const percent = Math.abs(newY / this.imageHeight) // 如果列表下拉的话,图片scale放大 if(newY > 0) { scale = 1 + percent zIndex = 14 } ``` ### 能力检测 检查浏览的供应商 [6-13] > ## 播放器页面 [第七章] ### 播放器Vuex数据设计[7-2] 播放器数据为全局的 播放状态 ### 播放器Vuex数据设计[7-3] > > 新建 commponents/player/plyer.vue 页面 > > 定义在APP.vue里面 > ### 播放器展开收起动画 [7-6] 安装 create-keyframe-animation > > npm install create-keyframe-animation --save > ### 播放器播放歌曲功能实现[7-8] > > > ### 播放器播放歌曲前进后退功能实现[7-9] 改变当前播放歌曲索引 修改currentIndex 切换播放歌曲太快会引发程序上面的错误 解决问题:player.vue 添加 `@canplay="ready"、 `@error="error"` ``` html ``` 切换歌曲的时候进行控制 ``` js data() { return { songReady: false } } ready(){ this.songReady = true }, ``` 在next和prev函数开始进行判断 ``` js // 如果songReady还没有ready的时候就不进行,直接return 掉 if(!this.songReady) { return }, ``` ``` ``` ### 播放器播放时间获取和更新[7-11] > > > ### 播放器progress-bar.vue进度条组件实现[7-12] ### 实现min播放器进度条[7-15] 新建 progress-circle ### 播放模式切换功能实现[7-16] ### 播放器歌词数据解析[7-19] 安装 js-base64 转化 歌词格式 npm install js-base64 --save npm install lyric-parser --save ### 播放器歌词滚动列表实现[7-21] ### 播放器歌词左右滑动实现[7-22] ### 播放器剩余功能实现[7-23] 边界情况的处理: 假设只有一条歌曲: ### 播放器底部播放器适配+mixin使用 ## 歌单详情页[第八章] ### 歌单详情页布局介绍Vuex实现路由数据通讯[8-1] 新建文件 @/components/disc/disc.vue 修改router/index.js路由 给recommend添加子路由 ``` { path: '/recommend', name: 'Recommend', component: Recommend, children: [ { path: ':id', component: Disc } ] }, ``` 在recommend.vue 里面引入 ### 歌单详情页面抓取[8-2] 使用axios 进行代理 无法直接获取数据 __webpack.dev.config.js__ ``` // 获取歌单列表详情数据 app.get('/api/getSongList', function (req, res) { var url = 'https://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg' axios.get(url, { headers: { referer: 'https://y.qq.com/', host: 'c.y.qq.com' }, params: req.query }).then((response) => { res.json(response.data) }).catch((e) => { console.log(e) }) }) ``` @/api/recommend.js ``` // 获取歌单列表详情数据 export function getSongList (disstid) { const url = '/api/getSongList' const data = Object.assign({}, commonParams, { uin: 0, format: 'json', notice: 0, needNewCode: 1, new_format: 1, pic: 500, disstid: disstid, type: 1, json: 1, utf8: 1, onlysong: 0, picmid: 1, nosign: 1, song_begin: 0, platform: 'h5', song_num: 100, _: +new Date() }) return axios.get(url, { params: data }).then((res) => { return Promise.resolve(res.data) }) } ``` ### 歌单详情数据处理和应用[8-3] common/js/song.js ``` // 歌曲列表详情数据 export function creatSongList (musicData) { return new Song({ id: musicData.id, mid: musicData.mid, singer: filterSinger(musicData.singer), name: musicData.name, album: musicData.albumname, duration: musicData.interval, image: `https://y.gtimg.cn/music/photo_new/T002R300x300M000${musicData.album.mid}.jpg?max_age=2592000`, url: `http://ws.stream.qqmusic.qq.com/C100${musicData.mid}.m4a?fromtag=0&guid=126548448` }) } function filterSinger(singer) { let ret = [] if (!singer) { return '' } singer.forEach((s) => { ret.push(s.name) }) return ret.join('/') } ``` 点击列表,跳转到disc.vue页面 这里是抓取的数据 push到结果里面(creatSongList) disc.vue ``` if (musicData.id && musicData.album) { ret.push(creatSongList(musicData)) } ``` ## 排行榜页面[第九章] ### 排行榜页面布局介绍给排行榜数据抓取[9-1] 新建@/components/rank/rank.vue 排行榜页面 新建 @/api/rank.js 进行排行歌单数据抓取 ### 排行榜数据应用[9-2] ### 榜单详情以及布局介绍及Vuex实现数据通讯[9-3] 新建@/components/top-list/top-list.vue 组件 在 router/index.js里面进行引用 ### 榜单详情页面 数据抓取和应用[9-4] ### 带排行榜song-list组件扩展和应用[9-5] ## 搜索页面 [第十章] ### 搜索页面功能及布局介绍[10-1] ### 搜索页面search-box组件开发[10-2] 新建 @/base/search-box/search-box.vue组件 v-model="query" 双向绑定 `` 如果有query的话才显示叉号图标 ### 搜索页面热门搜索数据抓取和应用[10-3] 新建@api/search.js ### 搜索页面suggest组件开发[10-4]-[10-10] [10-5] 10 报错 ``` js mutate vuex store state outside mutation handlers. at assert ``` 原因: 不要在 mutation 函数之外去修改 解决方法: 添加 `slice()` 方法,返回其副本 然后修改副本 ``` js let playlist = state.playlist.slice() let sequenceList = state.sequenceList.slice() ``` #### 边界情况的处理[10-10] 新建@/base/no-result/no-result.vue 文件 输入/删除 搜索时当停止的时候进行请求数据 [input 输入截流] 实现: common/js/util.js 截流函数 在search-box.vue里面引入并使用它 ### 搜索页面搜索结果保存功能实现[10-11]-[10-13] 搜索历史 安装 good-storage npm install good-storage --save 保存搜索历史 ### 搜索页面search-list组件功能实现[10-14]-[10-15] ### 搜索页面剩余功能实现[10-18] #### 弹窗组件的实现 新建文件 @/base/confirm/confirm.vue `````` ### 歌曲列表组件[第十一章] #### 歌曲列表组件布局和功能介绍[11-1] 新建文件 @/components/playlist/playlist.vue #### 歌曲列表组件显示和隐藏的控制[11-2] #### 歌曲列表组件播放列表的实现[11-3]-[11-9] #### [11-12] 新建文件 @/base/add-song/add-song.vue @/base/switches/switches.vue 绑定点击事件`@click="switchItem(index)` ``` js
  • {{item.name}}
  • ``` ``` 点击切换按钮 ``` js methods: { // 点击之后派发 switch 事件, 在父组件内用 @switch="switchItem" // 同时把index传递到父组件 switchItem(index) { this.$emit('switch', index) } } ``` ```` 父组件add-song.vue添加`@switch="switchItem"` ``` ``` ``` switchItem(index) { this.currentIndex = index } ``` ### [第十二章]用户中心页面 ### [第十三章]编译打包 新建 prod.server.js npm run build node prod.server.js 对路由进行异步加载 ``` js import Recommend from 'components/recommend/recommend' const Recommend = (resolve) => { import ('components/recommend/recommend').then((module) => { resolve(module) }) } ```