【八】listview组件
关于专题【vue开发音乐App】
何为listview?简单来说就是类似于我们手机自带的通讯录列表、音乐APP的歌手列表、外卖APP的分类菜单……,本文介绍的listview组件具备以下特性:
列表数据按照一定的分组依据(如热门、A、B、C等)进行分组后有序排列;
每组数据的顶部都有以该组名称命名的头部标签,用户滑动列表,相邻的两个头部标签之间会产生替换动画;
右侧提供快速定位的导航条,类似锚点,除简单的点击触发以外,还支持手指滑动,十分接近原生体验。
该组件实现难度较大,文章篇幅也较长,但是其中也包含了众多精彩的前端技能,所以还是希望大家能花点时间阅读本文并加以实践。
一、处理数据
数据通过jsonp跨域调用QQ音乐真实线上接口获取( 该部分不是本文重点,所以省略 ),获取到的数据是扁平的:
list: [
{
Farea: '1',
Fattribute_3: '3',
Fattribute_4: '0',
Fgenre: '0',
Findex: 'X',
Fother_name: 'Joker',
Fsinger_id: '5062',
Fsinger_mid: '002J4UUk29y8BY',
Fsinger_name: '薛之谦',
Fsinger_tag: '541,555',
Fsort: '1',
Ftrend: '0',
Ftype: '0',
voc: '0'
},
{
Farea: '0',
Fattribute_3: '2',
Fattribute_4: '0',
Fgenre: '0',
Findex: 'Z',
Fother_name: 'Jay Chou',
Fsinger_id: '4558',
Fsinger_mid: '0025NhlN2yWrP4',
Fsinger_name: '周杰伦',
Fsinger_tag: '541,555',
Fsort: '2',
Ftrend: '0',
Ftype: '0',
voc: '0'
},
// 省略后面98个
]
这种数据不能直接使用,需要处理成如下数据结构:
list: [
{
title: '热门',
items: [
{
id: '002J4UUk29y8BY',
name: '薛之谦',
avatar: 'https://y.gtimg.cn/music/photo_new/T001R300x300M000002J4UUk29y8BY.jpg?max_age=2592000'
},
{
id: '0025NhlN2yWrP4',
name: '周杰伦',
avatar: 'https://y.gtimg.cn/music/photo_new/T001R300x300M0000025NhlN2yWrP4.jpg?max_age=2592000'
},
...
]
},
{
title: 'A',
items: [
{
id: '0020PeOh4ZaCw1',
name: 'Alan Walker (艾伦·沃克)',
avatar: 'https://y.gtimg.cn/music/photo_new/T001R300x300M0000020PeOh4ZaCw1.jpg?max_age=2592000'
},
...
]
},
...
]
如何得到这种结构的数据?代码如下:
import Singer from 'common/js/singer'
const HOT_SINGER_LEN = 10
const HOT_NAME = '热门'
...
_normalizeSinger(list) {
let map = {
hot: {
title: HOT_NAME,
items: []
}
}
list.forEach((item, index) => {
// 只取前十名歌手作为热门
if (index < HOT_SINGER_LEN) {
// Singer类通过歌手id可以生成avatar链接
map.hot.items.push(new Singer({
name: item.Fsinger_name,
id: item.Fsinger_mid
}))
}
const key = item.Findex
if (!map[key]) {
map[key] = {
title: key,
items: []
}
}
map[key].items.push(new Singer({
name: item.Fsinger_name,
id: item.Fsinger_mid
}))
})
// 为了得到有序列表,我们需要处理 map
let ret = []
let hot = []
for (let key in map) {
let val = map[key]
if (val.title.match(/[a-zA-Z]/)) {
ret.push(val)
} else if (val.title === HOT_NAME) {
hot.push(val)
}
}
ret.sort((a, b) => {
// 按照“A-Z”的字母顺序排列
return a.title.charCodeAt(0) - b.title.charCodeAt(0)
})
return hot.concat(ret)
}
Singer是抽象出来的类,作用是统一生成_normalizeSinger()方法中被push进items数组的单个歌手信息(id、name、avatar ),详细实现如下:
// common/js/singer
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`
}
}
二、代码实现
src/base/listview/listview.vue:
三、调用
-
{{group.title}}
- {{item.name}}
- {{item}}
发表评论 (审核通过后显示评论):