# 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)
})
}
```