vuejs开发音乐播放器(一):歌手页面
来源:互联网 发布:网络硬盘录像机的用途 编辑:程序博客网 时间:2024/05/17 01:43
1、首先看先要实现的功能和界面。
2、具体有如下3个。
(1)歌手列表:用vuejs中的使用QQ音乐接口,抓取列表,并用better-scroll实现滚动。首先我们去qq音乐官网抓包,使用ajax、jsonp获取接口数据。定义好请求参数和头部。获取到数据后,经过_normalizeSinger函数将Fsinger_mid将歌手名字按英文字母正序排序后输出到新的数组
(2)滚动时固定标题栏:通过singer.vue中ES6代码实现。
(3)右侧固定索引:click点击定位,touchmove滑动定位,锚点定位,高亮显示,具体看listview.vue的代码
3、具体代码实现如下。由于篇幅有限,只贴上重要的部分,有想了解的可以加我好友探讨问题。
1、jsonp.js
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) } }) })}
2、config.js
export const commonParams = { g_tk: 5381, inCharset: 'utf-8', outCharset: 'utf-8', notice: 0, format: 'jsonp'}export const options = { param: 'jsonpCallback'}export const ERR_OK = 0
3、singer.js(引入前两个文件)
import jsonp from 'common/js/jsonp'import {commonParams, options} from './config'export function getSingerList() { const url = 'https://c.y.qq.com/v8/fcg-bin/v8.fcg' const data = Object.assign({}, commonParams, { channel: 'singer', page: 'list', key: 'all_all_all', pagesize: 100, pagenum: 1, hostUin: 0, loginUin: 0, needNewCode: 0, platform: 'yqq', g_tk: 5381, inCharset: 'utf8', outCharset: 'utf-8', notice: 0, format: 'jsonp' }) return jsonp(url, data, options)}
4、scroll.vue
<template> <div ref="wrapper"> <slot></slot> </div></template><script type="text/ecmascript-6"> import BScroll from 'better-scroll' export default { props: { probeType: { type: Number, default: 1 }, click: { type: Boolean, default: true }, data: { type: Array, default: null }, listenScroll: { type: Boolean, default: false } }, mounted() { setTimeout(() => { this._initScroll() }, 20) window.addEventListener('resize', () => { if (!this.slider) { return } this._setSliderWidth(true) this.slider.refresh() }) }, methods: { _initScroll() { if (!this.$refs.wrapper) { return } this.scroll = new BScroll(this.$refs.wrapper, { probeType: this.probeType, click: this.click }) if (this.listenScroll) { let me = this this.scroll.on('scroll', (pos) => { me.$emit('scroll', pos) }) } }, enable() { this.scroll && this.scroll.enable() }, disable() { this.scroll && this.scroll.disable() }, refresh() { this.scroll && this.scroll.refresh() }, scrollTo() { this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments) }, scrollToElement() { this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments) } }, watch: { data() { setTimeout(() => { this.refresh() }, 20) } } }</script><style scoped lang="stylus" rel="stylesheet/stylus"></style>
5、listview.vue
<template> <scroll ref="listview" class="listview" :data="data" :listenScroll="listenScroll" @scroll="scroll" :probeType="probeType" > <ul> <li v-for="group in data" class="list-group" ref="listGroup"> <h2 class="list-group-title">{{group.title}}</h2> <uL> <li v-for="item in group.items" class="list-group-item"> <img class="avatar" v-lazy="item.avatar"> <span class="name">{{item.name}}</span> </li> </uL> </li> </ul> <div class="list-shortcut" @touchstart="onShortcutTouchStart" @touchmove.stop.prevent="onShortcutTouchMove"> <ul> <li v-for="(item,index) in shortcutList" class="item" :class="{'current':currentIndex===index}" :data-index="index" > {{item}} </li> </ul> </div> <div class="list-fixed" v-show="fixedTitle" ref="fixed"> <h1 class="fixed-title"> {{fixedTitle}} </h1> </div> <div class="loading-content" v-show="!data.length"> <loading></loading> </div> </scroll></template><script type="text/ecmascript-6"> import Loading from 'base/loading/loading' import Scroll from 'base/scroll/scroll' const ANCHOR_HEIGHT = 18 const TITLE_HEIGHT = 30 export default { props: { data: { type: Array, default: [] } }, created() { this.touch = {} this.listenScroll = true this.listenHeight = [] this.probeType = 3 }, data() { return { scrollY: -1, currentIndex: 0, diff: -1 } }, computed: { shortcutList() { return this.data.map((group) => { return group.title.substring(0, 1) }) }, fixedTitle() { if (this.scrollY > 0) { return '' } return this.data[this.currentIndex] ? this.data[this.currentIndex].title : '' } }, methods: { getData(el, name, val) { const prefix = 'data-' if (val) { return el.setAttribute(prefix + name, val) } return el.getAttribute(prefix + name) }, onShortcutTouchStart(e) { let anchorIndex = this.getData(e.target, 'index') let firstTouch = e.touches[0] this.touch.y1 = firstTouch.pageY this.touch.anchorIndex = anchorIndex this._scrollTo(anchorIndex) }, onShortcutTouchMove(e) { let firstTouch = e.touches[0] this.touch.y2 = firstTouch.pageY let delta = (this.touch.y2 - this.touch.y1) / ANCHOR_HEIGHT | 0 let anchorIndex = parseInt(this.touch.anchorIndex) + delta this._scrollTo(anchorIndex) }, scroll(pos) { this.scrollY = pos.y }, _scrollTo(index) { console.log(index) if (index === null) { return } if (index < 0) { index = 0 } else if (index > this.listenHeight - 2) { index = this.listenHeight - 2 } this.scrollY = -this.listenHeight[index] this.$refs.listview.scrollToElement(this.$refs.listGroup[index], 0) }, _calculateHeight() { this.listenHeight = [] const list = this.$refs.listGroup let height = 0 this.listenHeight.push(height) for (let i = 0; i < list.length; i++) { let item = list[i] height += item.clientHeight this.listenHeight.push(height) } } }, watch: { data() { setTimeout(() => { this._calculateHeight() }, 20) }, scrollY(newY) { const listenHeight = this.listenHeight // when the top newY > 0 if (newY > 0) { this.currentIndex = 0 return } // when the middle for (let i = 0; i < listenHeight.length - 1; i++) { let height1 = listenHeight[i] let height2 = listenHeight[i + 1] if (!height2 || (-newY >= height1 && -newY < height2)) { this.currentIndex = i this.diff = height2 + newY console.log(this.currentIndex) return } } // when the middle this.currentIndex = this.listenHeight - 2 }, diff(newVal) { let fixedTop = (newVal > 0 && newVal < TITLE_HEIGHT ? newVal - TITLE_HEIGHT : 0) if (this.fixedTop === fixedTop) { return } this.fixedTop = fixedTop this.$refs.fixed.style.transform = 'translate3d(0,' + fixedTop + 'px,0)' } }, components: { Scroll, Loading } }</script><style scoped lang="stylus" rel="stylesheet/stylus"> @import "~common/stylus/variable" .listview position: relative width: 100% height: 100% overflow: hidden background: $color-background .list-group padding-bottom: 30px .list-group-title height: 30px line-height: 30px padding-left: 20px font-size: $font-size-small color: $color-text-l background: $color-highlight-background .list-group-item display: flex align-items: center padding: 20px 0 0 30px .avatar width: 50px height: 50px border-radius: 50% .name margin-left: 20px color: $color-text-l font-size: $font-size-medium .list-shortcut position: absolute z-index: 30 right: 0 top: 50% transform: translateY(-50%) width: 20px padding: 20px 0 border-radius: 10px text-align: center background: $color-background-d font-family: Helvetica .item padding: 3px line-height: 1 color: $color-text-l font-size: $font-size-small &.current color: $color-theme .list-fixed position: absolute top: 0 left: 0 width: 100% .fixed-title height: 30px line-height: 30px padding-left: 20px font-size: $font-size-small color: $color-text-l background: $color-highlight-background .loading-container position: absolute width: 100% top: 50% transform: translateY(-50%)</style>
6、singer.vue
<template> <div class="singer"> <listview :data="singers"></listview> </div></template><script type="text/ecmascript-6">import {getSingerList} from 'api/singer'import {ERR_OK} from 'api/config'import Singer from 'common/js/singer'import Listview from 'base/listview/listview'const HOT_NAME = '热门'const HOT_SINGER_LEN = 10export default { data() { return { singers: [] } }, created() { this._getSingerList() }, methods: { _getSingerList() { getSingerList().then((res) => { if (res.code === ERR_OK) { this.singers = this._normalizeSinger(res.data.list) console.log(this.singers) } }) }, _normalizeSinger(list) { let map = { hot: { title: HOT_NAME, items: [] } } list.forEach((item, index) => { if (index < HOT_SINGER_LEN) { map.hot.items.push(new Singer({ id: item.Fsinger_mid, name: item.Fsinger_name })) } const key = item.Findex if (!map[key]) { map[key] = { title: key, items: [] } } map[key].items.push(new Singer({ id: item.Fsinger_mid, name: item.Fsinger_name })) }) let hot = [] let ret = [] 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) => { return a.title.charCodeAt(0) - b.title.charCodeAt(0) }) return hot.concat(ret) } }, components: { Listview, Singer }}</script><style scoped lang="stylus" rel="stylesheet/stylus"> .singer position: fixed top: 88px bottom: 0 width: 100%</style>
阅读全文
0 0
- vuejs开发音乐播放器(一):歌手页面
- vuejs开发音乐播放器(二):从歌手页面到歌手详情页面的子路由跳转
- vuejs开发音乐播放器(二):单歌手歌单列表界面
- android音乐播放器开发(一)
- Android开发本地及网络Mp3音乐播放器(十三)网络音乐搜索功能实现,歌名歌手专辑名搜索
- 音乐播放器(一)
- 基于Vue2.0的音乐播放器(2)——歌手模块
- 如何获取酷我音乐播放器中的歌手写真
- Android开发之音乐播放器(一)
- 使用SVG开发音乐播放器(一)
- Android 超简单音乐播放器(三)根据歌曲名或者歌手搜索本地音乐(EditText监听)
- iOS开发之网络音乐播放器(SC音乐)(一)
- 音乐播放器开发
- android 音乐播放器(一)
- 极简音乐播放器(一)
- 迷你音乐播放器(一)
- iOS 音乐播放器(一)
- Android开发----音乐播放器(扫描本地音乐)
- iOS iPhone X 适配
- Publish ROS message from terminal
- Basic_Calculator
- Maven:pom配置文件optional含义
- vbox 共享文件夹
- vuejs开发音乐播放器(一):歌手页面
- bzoj 1206: [HNOI2005]虚拟内存
- 如何将从数据库中读出的带有html标签的字符串,让标签起效,显示在前台页面
- STL lb,ub
- spin and mutex lock
- push本地代码到github出错
- layer.close()关闭进度条和Iframe窗
- HDU 1254 推箱子(双重bfs)
- Java post请求发送json数据在filter中解析方法