Vue-music项目概述
这是一个基于vue2.x全家桶和真实线上数据接口开发的一个媲美原生的移动端音乐App,已完成页面包括有歌单推荐页,歌手列表页,歌手详情页,播放器页面,排行榜页面和搜索页面。
要点总结
Vue
<router-link>
:通过to
属性指定目标地址;配置tag
属性生成别的标签,当目标路由成功激活时,将自动在tag
生成的标签上自动设置router-link-active
类名<router-view>
:用于构建单页应用时,渲染指定路由对应的组件,可当作是要匹配组件的容器<keep-alive>
:在组件切换过程中将状态保留在内存中,防止重复渲染DOM<slot>
:Vue的内容分发机制,即可以将父组件的内容分发到子组件的指定位置中,<slot>
则作为承载分发内容的出口
JS
Promise
:异步编程的一种解决方案,在项目中的运用:
export default function jsonp(url, data, option) {
url += (url.indexOf('?') < 0 '?' : '&') + param(data)
return new Promise((resolve, reject) => {
originJSONP(url, option, (err, data) => {
if (!err) {
resolve(data)
} else {
reject(err)
}
})
})
}
Object.assign()
:用于对象的合并,将源对象的所有可枚举属性,复制到目标对象。第一个参数是目标对象,后面的参数都是源对象
const data = Object.assign({}, commonParams, {
platform: 'h5',
uin: 0,
needNewCode: 1
})
setTimeout(fn, 20)
:JS线程执行完毕后一个Tick的时间约17ms内DOM就有可以渲染完毕,所以setTimeout(fn, 20)
是非常稳妥的写法
CSS
Stylus
:编写模块化的CSSFlex
:弹性布局,实现常见的移动设备的响应式布局
库的使用
better-scroll
:
- 易错:
better-scroll
只会处理容器的第一个子元素的滚动;且子元素的宽度(或高度)一定要大于容器的宽度(或高度)才可以滚动;当一个页面出现不同滚动需求时(例如歌单推荐页即有横向又有纵向的滚动),可进行嵌套使用,但必须用一个容器将两部分滚动包裹在一起 - slider组件:需配置参数值
snap:true
,另外设置snapLoop:true
表示无缝循环轮播,snapThreshold:0.3
表示手指滑动大于这个阈值则滑动到下一页,snapSpeed:400
表示轮播图切换的动画时间 - 事件:
scrollEnd
表示滚动结束时触发
- 函数:
refresh()
:强制scroll重新计算,当better-scroll中的元素发生变化的时候调用此方法getCurrentPage()
:获取滚动的当前页,返回对象结构为{x, y, pageX, pageY}
,x,y代表滚动横向和纵向的位置;pageX
,pageY
表示横向和纵向的页面索引。用法如:getCurrentPage().pageX
goToPage(x, y, time, easing)
:滚动到对应的页面,x表示横向页面索引,y表示纵向页面索引,time
表示动画,easing
表示缓动函数(可省略)
- 易错:
jsonp
:获取轮播图数据时用到,传入的url需做字符串处理,data需进行encodeURIComponent()
编码处理,再结合new Promise()
异步获取数据axios
:基于promise
的HTTP库,可以用在浏览器和node.js
中,项目中用的最多的通过代理后端服务器获取数据的手段
// 歌单数据获取
before(app) {
app.get('/api/getDiscList', function(req, res) {
var url = "https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg"
axios.get(url, {
header: {
referer: 'http://y.qq.com',
host: 'c.y.qq.com'
},
params: req.query
}).then((response) => {
res.json(response.data)
}).catch((e) => {
console.log(e)
})
})
}
export function getDiscList() {
const url = '/api/getDiscList'
const data = Object.assign()
return axios.get(url, {
params: data
}).then((res) => {
return Promise.resolve(res.data)
})
}
vue-lazyload
:懒加载图片,优化用户体验
轮播图
- 设置轮播宽度:
Bscroll
设置snapLoop
时会自动克隆两个轮播图插在前后位置,为了保证轮播图无缝切换,需要增加两个宽度;同时加入窗口变化时不再增加宽度的限制
if (this.loop && !isResize) {
width += 2*sliderWidth
}
初始化dots:dots的数量由轮播图数量决定,因此需在设置克隆插入轮播之前进行
初始化滚动:通过
getCurrentPage()
获取当前滑动页的索引赋值给currentPageIndex
,与dots的index
比较是否相等,以此添加active
自动播放:自定义定时器结合
goToPage()
跳转到相应的页面
_play() {
let pageIndex = this.currentPageIndex + 1
if (this.loop) {
pageIndex += 1
}
this.timer = setTimeout( ()=> {
this.slider.goToPage(pageIndex, 0, 400)
}, this.interval)
}
清除定时器:每次手指滑动时都应清除定时器,避免索引值的获取发生错乱;组件销毁时都应清除定时器达到释放内存的目的
监听窗口变化:为了保证窗口变化时依旧能够正常轮播,应监听
resize
事件来重新渲染轮播图并计算宽度
window.addEventListener('resize', ()=> {
if (!this.slider) {
return
}
this._setSliderWidth(true)
this.slider.refresh()
})
歌手列表数据聚合
// 定义Singer类(相当于ES5的构造函数)创建属性,处理avatar字段
export default class Singer {
constructor({id, name}) {
this.id = id
this.name = name
this.avatar = `https://y.gtimg.cn/music/photo_new/T001R300x300M000${id}.jpg?max_age=2592000`
}
}
_normalizeSinger(list) {
let map = {
hot: {
title: