基于Vue2.x开发的音乐播放器app(推荐界面+懒加载+axios获取后端接口实现)

1、项目开发需求分析:

包含四个层面——

(1)推荐模块

(2)歌手模块

(3)排行模块

(4)搜索模块

2、项目开发流程

(1)搭建项目:借助vue-cli脚手架工具,具体请参考博客: ...;

由于项目存放在本地电脑E盘VueTest目录下,

cd E:\VueTest


图1:切换项目存放目录、vue-cli搭建初始项目

通过脚手架vue-cli工具搭建项目

vue init webpack vue-music

选择配置项目相关webpack

                    

(2)进入项目vue-music

cd vue-music

安装项目node_mudules依赖(在这里采用淘宝镜像cnpm,可加快安装效率)

cnpm install

上述流程具体操作见(图2:安装项目依赖)

    基于Vue2.x开发的音乐播放器app(推荐界面+懒加载+axios获取后端接口实现)_第1张图片

                                         图2:安装项目依赖

在本地加载该项目工程文件

npm run dev


                     图3:搭建成功界面

当看到localhost:8080/8081时,说明项目工程环境搭建成功。

基于Vue2.x开发的音乐播放器app(推荐界面+懒加载+axios获取后端接口实现)_第2张图片

                                        图4:本地搭建环境成功

当显示上述界面,则表示vue-cli脚手架搭建的vue-music项目成功。


(3)在编辑器中打开该项目工程文件(在该环节中我采用的编辑器:VS Code)

项目目录中所以开发主要基于src目录作为主载

基于Vue2.x开发的音乐播放器app(推荐界面+懒加载+axios获取后端接口实现)_第3张图片

图5:项目工程目录

2.3-1——目录src

api:主要存放后台请求相关的代码,包括ajax,jsonp等,

有.gitkeep文件表示虽为空,但可上传至git上

common:主要存放通用的静态资源,包括字体图标fonts、图片images、脚本文件js库、样式文件stylus

   stylus——

base.styl:基础样式,引用variable.styl

variable.styl:以“变量定义”方式引入样式文件(颜色、字体定义规范)

icon.styl:字体图标样式文件

index.styl:引入reset、base、icon三者样式文件

mixin.styl:定义一些函数,方便组件.vue文件中引用

reset.styl:重置样式文件

基于Vue2.x开发的音乐播放器app(推荐界面+懒加载+axios获取后端接口实现)_第4张图片

图6:common目录下stylus 

components:主要存放项目中组件化.vue文件

router:主要存放静态路由相关代码index.js

store:主要存放vuex相关代码

App.vue:

main.js:主要存放渲染app文件的js脚本

2.3-2:更改相关文件

在build文件夹下,webpack.base.conf.js中

resolve: {
extensions: [ '.js', '.vue', '.json'],
alias: {
'src' : resolve( 'src'),
'common' : resolve( 'src/common')
}
},

这样,在项目中可以这么使用,如下:

import 'common/stylus/index.styl'


3、页面骨架开发

(1)页面入口+header

首先,package.json文件做以下更改

"dependencies": {
"babel-runtime": "^6.26.0",
"vue": "^2.5.2",
"vue-router": "^3.0.1",
"fastclick": "^1.0.6"
},

在“devDependencis”下,新增下面babel-polyfill、stylus、stylus-loader三个依赖,

运行cnpm install

"stylus ": "^0.54.5",
"babel-polyfill": "^6.2.0",
"stylus-loader": "^3.0.1"


(2)路由配置+顶导组件开发

router静态路由——根组件默认指向

vue-router(index.js)——new Vue({ router })(main.js)——(App.vue)

main.js——babel-polyfill、fastClick


在http://localhost:8080/#中可以用静态路由vue-router实现界面间切换

基于Vue2.x开发的音乐播放器app(推荐界面+懒加载+axios获取后端接口实现)_第5张图片

图7:vue-router实现界面跳转

解析:由于在项目工程文件中指定根路径path:/recommend,所以默认为该界面,同时点击不同的tab选项列   表,可由静态路由进入不同的组件。

import Router from 'vue-router'
Vue. use( Router)

export default new Router({
routes: [
// 根组件默认的指向
{
path: '/',
component: Recommend
},
{
path: '/recommend',
component: Recommend
},
{
path: '/singer',
component: Singer
},
{
path: '/rank',
component: Rank
},
{
path: '/search',
component: Search
}
]
})


4、推荐模块开发

locahost:8080/#/recommend

疑难点:

a、数据获取——线上真实数据,非模拟。用qq音乐进行抓取数据,(采用jsonp进行抓取线上数据)

                       基于Vue2.x开发的音乐播放器app(推荐界面+懒加载+axios获取后端接口实现)_第6张图片

图8:qq音乐播放器抓取数据

b、jsonp原理:可参考github地址(https://github.com/webmodules/jsonp

基于Vue2.x开发的音乐播放器app(推荐界面+懒加载+axios获取后端接口实现)_第7张图片

图9:github-jsonp地址

c、在index.js可查看具体实现原理

(1)Install

Install for node.js or browserify usingnpm:

$ npm install jsonp

Install for component(1) using component:

$ component install LearnBoost/jsonp

Install for browser using bower:

$ bower install jsonp

(2)API

jsonp(url, opts, fn)

  • url (String) url to fetch
  • opts (Object), optional
    • param (String) name of the query string parameter to specify the callback (defaults to callback)
    • timeout (Number) how long after a timeout error is emitted. 0 to disable (defaults to 60000)
    • prefix (String) prefix for the global callback functions that handle jsonp responses (defaults to __jp)
    • name (String) name of the global callback functions that handle jsonp responses (defaults to prefix + incremented counter)
  • fn callback
操作——在package.json下定义jsonp,再cnpm install安装该依赖

"dependencies": {
"babel-runtime": "^6.26.0",
"vue": "^2.5.2",
"vue-router": "^3.0.1",
"fastclick": "^1.0.6",
"jsonp": "^0.2.1"
},


jsonp的封装“./src/common/js/jsonp.js”

// jsonp封装(用promise实现封装)
import originJSONP from 'jsonp'

export default function jsonp( url, data, option) {
// url拼接
url += ( url. indexOf( '?') < 0 ? '?' : '&') + param( data)
// Promise()回调函数,类似于callback,三种状态:pending(进行中)/resolve(已完成)/reject(已失败)
return new Promise(( resolve, reject) => {
originJSONP( url, option, ( err, data) => {
if (! err) {
resolve( data)
} else {
reject( err)
}
})
})
}

// 将data转换为json格式
function param( data) {
let url = ''
for ( var k in data) {
let value = data[ k] !== undefined ? data[ k] : ''
url += `& ${ k } = ${ encodeURIComponent( value) } `
}
return url ? url. substring( 1) : ''
}

jsonp使用:对其以promise方式封装,同时在/api目录下封装获取数据的方法

(1)轮播图

4.1-1数据抓取

components——recommend.vue“slide-wrapper”

api——recommend.js、config.js

js——jsonp.js

当上述文件编译成功,在开发者工具F12下的console控制台程序,会显示如下:

基于Vue2.x开发的音乐播放器app(推荐界面+懒加载+axios获取后端接口实现)_第8张图片

图10:qq音乐轮播图数据抓取成功界面


4.1-2:轮播图组件开发

目录base基础目录——src/base/slider/slider.vue,

slot插槽

< div class= "slider" >
< div class= "slider-group" >
< slot > slot >
div >

< div class= "dots" >

div >
div >

轮播图模块实现:

   实现方式很多,在这里借助better-scroll库实现Slider组件开发

   属性:snap——false,针对slider开发,普通列表滚动不需要配置

         snap——false 是否可以无缝循环轮播

 snapSpeed——400,轮播图切换的动画时间

4.1-2-1:slider-group(轮播图横向点击无缝滚动)

a、初始化Scroll

首先,在package.json中安装依赖,并在命令行中执行“cnpm install”

"dependencies": {
"better-scroll": "^1.4.2",
}

其次,在slider.vue组件中引入该库

import BScroll from "better-scroll"


b、计算setSliderWidth,在methods方法中,定义_setSliderWidth()

// 设置轮播宽度
_setSliderWidth() {
// 获得列表元素多少
this. children = this. $refs. sliderGroup. children

// 设置宽度/每个slider宽度均为元素的clientWidth
let width = 0
let sliderWidth = this. $refs. slider. clientWidth
for( let i= 0; i< this. children. length; i++) {
// 先获取每个子元素
let child = this. children[ i]
// import addClass方法,并传入参数
addClass( child, 'slider-item')
// 设置每个child的宽度
child. style. width = sliderWidth + 'px'
width += sliderWidth
}

// loop需要克隆2倍宽度
if( this. loop) {
width += 2* sliderWidth
}
this. $refs. sliderGroup. style. width = width + 'px'
},

c、初始化轮播图slider,methods中_initSlider()方法,此时引用a中BScroll插件

// 初始化轮播图
_initSlider() {
// 绑定DOM元素slider,options配置
this. slider = new BScroll( this. $refs. slider, {
// 只允许横向滚动,不允许纵向
scrollX: true,
scrollY: false,
momentum: false, // 惯性
snop: true, //无缝滚动
snopLoop: this. loop,
snopThreshold: 0.3,
snopSpeed: 400,
click: true
})
}

4.1-2-2:dots设置自动轮播

为了实现该功能,必须在初始化initSlider()之前初始化dos,

首先,在data()中定义一个dots对象

data() {
return {
dots: []
}
},


其次,在methods方法中定义_initDots()

// 初始化dots
_initDots() {
this. dots = new Array( this. children. length)
},

最后,在mounted钩子里调用该方法,在_initSlider()之前

// mounted钩子
mounted() {
setTimeout(() => {
this. _setSliderWidth()
this. _initDots()
this. _initSlider()
}, 20);
},

测试:当不清除定时器时,由于在自动播放autoPlay()之前,为手动播放,所以需要清除clearInteral()

// 给slider绑定scrollEnd()事件() => {}回调函数
this. slider. on( 'scrollEnd', () => {
// 表示第几个子元素
let pageIndex = this. slider. getCurrentPage(). pageX
if( this. loop) {
pageIndex -= 1
}
this. currentPageIndex = pageIndex

// 测试:由于上述代码运行只滚动一次,所以该事件scrollEnd有bug,对其添加autoPlay进行测试
if( this. autoPlay) {
// 由于在自动播放的时候,是手动播放,所以需要clear定时器
clearInterval( this. timer)
this. _play()
}
})

运行效果图如下:(注意:可以自动播放,截取的是静态图)

基于Vue2.x开发的音乐播放器app(推荐界面+懒加载+axios获取后端接口实现)_第9张图片

优化: 当发现在控制台上切换不同的屏幕大小的时候,界面显示出现错误,如下:

基于Vue2.x开发的音乐播放器app(推荐界面+懒加载+axios获取后端接口实现)_第10张图片


解析:上述bug出现的主要原因是因为_setSliderWidth()中sliderWidth出现了小问题,即window下的resize

解决办法:监听一个window下resize事件

// 优化sliderWidth宽度不一的问题
window. addEventListener( 'resize', () => {
// 当slider未初始化
if(! this. slider) {
return
}
// 判断是否有isResize(),
this. _setSliderWidth( true)
// 宽度发生变化,需要重新计算刷新以下slider
this. slider. refresh()
})


此外,在_setSliderWidth()事件,应该传入参数isResize做判断,同时执行函数时,初始下不需要isResize(),但到重新计算宽度时,就不能width*2

// 若loop自动播放为true,且不需要resize时,loop需要克隆2倍宽度
if( this. loop && ! isResize) {
width += 2* sliderWidth
}

重新编译后,会发现无论是在移动端进行测试,还是切换屏幕大小,在pc或Mac端测试,宽度均不会出现问题,

但是,当我们重新切换或者加载的时候,recommend.vue生命周期,以及相关数据均会重新加载一遍才会刷新到数据,导致体验差,

优化1:App.vue中,将router-view加一个keep-alive进行dom缓存

< keep-alive >
< router-vxew > router-view >
keep-alive >

优化2:slider.vue中,export default({})加一个destroyed()清除缓存定时器

// destroyed生命周期,当存在寄存器,元素销毁时机,清除资源
destroyed() {
clearTimeout( this. timer)
}

4.1-3:歌单列表组件开发

a、歌单数据接口分析

在这里抓取的是PC端歌单数据,地址:https://y.qq.com/portal/playlist.html

               基于Vue2.x开发的音乐播放器app(推荐界面+懒加载+axios获取后端接口实现)_第11张图片

从上述console控制台下NetWork  general下的requestUrl即为表单数据接口地址

https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg


b、实现原理

首先,定义接口获取函数。包括url以及data相关数据,在recommend.js

// 获取歌单接口数据
export function getDiscList() {
// 歌单接口url地址
const url = 'https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg'

// 定义表单接口数据
const data = Object. assign({}. commonParams, {
platform: 'yqq',
hostUin: 0,
needNewCode: 0,
categoryId: 10000000,
sortId: 5,
sin: 0,
ein: 29,
rnd: Math. random()
})

return jsonp( url, data, options)
}

其次,在recommend.vue组件下调用该获取接口数据函数

created() {
// 获取轮播图图片接口数据函数
this. _getRecommend(),
// 获取歌单接口数据函数
this. _getDiscList()
},

同时,在表头引入该函数

import { getRecommend, getDiscList} from 'api/recommend'

c、后端接口代理axios

  由于若使用jsonp进行数据抓取,会导致一些错误,因为qq音乐服务器端不会识别,只能在项目build目录下dev-server.js下,配置与qq音乐相同的headers——referer、host相同,这样服务器端识别完成,相当于后端代理的方法获取了后台的歌单接口数据。


  采用ajax http请求API axios库https://github.com/mzabriskie/axios

首先,package.json上写入axios,并在cmd命令行cnpm install安装依赖

"dependencies": {
"axios": "^0.17.1"
},

在build/dev-server.js中中,设置Axios后端接口代理,用于获取接口数据,再进行调取相应的api。

const axios = require( 'axios')
const app = express()

// define apiRoutes
const apiRoutes = express. Router()

// 后端接口代理
apiRoutes. get( '/getDiscList', function( req, res) {
// ajax库axios
const 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)
})
})

app. use( '/api', apiRoutes)


未完待续...(由于axios请求接口一直处于404失败状态,所以recommend组件结合dev.server.js配置未达到预期的效果,还需要做到后期的改善)


4.1-4:scroll滚动组件,scroll.vue

  由于scroll滚动适用于所有模块界面的滑动,所以作为一个组件进行开发,结合slot插槽进行使用

< template >
< div ref= "wrapper" >
< slot > slot >
div >
template >

  在

你可能感兴趣的:(Vue,Vue学习之旅)