Skip to content

X-Yin/vue-music

Repository files navigation

vue-music

A Vue.js project

Build Setup

# 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

# run unit tests
npm run unit

# run e2e tests
npm run e2e

# run all tests
npm test

项目总结

项目思路

  1. 首页的顶部为一个标题,右上角有个人中心的入口。标题下面是一个导航栏,分别有推荐、歌手、排行、搜索等模块,点击相应的模块可以切换到对应的页面。
  2. 推荐页面由轮播图和歌单列表组成,点击对应的歌单可以切换到相应的歌单详情页。
  3. 歌手页面由歌手列表组成,点击右边的字母索引可以滚动到对应的歌手区域。
  4. 排行页面由榜单列表组成,点击对应的榜单可以切换到对应的榜单详情页。
  5. 搜索页面由搜索框,热门搜索,搜索历史等模块组成。在搜索框输入要搜索的内容,搜索结果会在搜索框下部显示。
  6. 播放器内核由背景模糊的图片做背景,分别有专辑图片,进度条,歌词,播放器控制按钮等模块。

项目中出现的问题及解决方法

  • 页面初始加载完成后无法进行滚动:

由于移动端的滚动这里使用的是better-scroll插件,而歌曲资源是异步获取的,页面初始化完成后,歌曲资源还没有获取,所以这里better-scroll并不能正确的计算元素的高度。解决的办法是,抽象出一个scroll组件,并且传入一个参数data,给data加上一个监听器,当资源异步获取完成后,调用refresh方法,重新计算元素的高度

  • 歌曲的播放进度与歌词滚动不同步

这里歌词的滚动进度使用的是插件lyric-parser,它在初始化歌词对象以后会立即添加一个计时器,但是这个时候歌曲的播放地址可能还没有获取到,导致出现歌词已经开始滚动,但是歌曲还没有开始播放的问题。解决的办法是,audio标签在当浏览器能够开始播放指定的音频/视频时,发生 canplay 事件,可以为这个事件添加一个方法,当触发canplay事件的时候再获取歌词,这样在歌曲的播放地址获取到以后,才会获取歌词的数据。

  • 在播放模式改变的时候,歌曲的播放进度会从头开始

在播放模式改变的时候,相应的播放列表playlist也会发生改变,这个时候currentSong也会发生变化,会重新给audio标签赋一次src值,导致歌曲从头开始播放。解决的办法是,为currentSong添加一个监听器,如果newValue的id值和oldValue的id值相同就return。

  • 在播放器缩小到mini播放器的时候,歌单的最后一个li标签会被mini播放器挡住

解决的办法是,为playlist添加一个监听器,如果playlist.length !== 0,那么为歌单添加一个bottom值为60px,否则的话bottom值为0。由于这里有多个页面都具有相同的问题,所以采用复用性较高的mixins,在mixins.js中监听playlist, 并触发一个方法handlePlayList,来设置不同页面的bottom值。

  • 在个人中心里面点击播放喜爱的歌曲的时候,获取不到歌词

favoriteSongs的数据是缓存在localStorage里面的,获取歌词的接口的方法(getLyric)是在Song类中定义的,而从localStorage里面取出的是普通的对象并不是Song类,所以并没有getLyric这个方法。解决的办法是在点击每一首歌的时候,重新用new Song(item)初始化Song类,为item添加获取歌词的方法。

核心组件及设计思路

  • musicList组件

推荐页面的歌单详情页和排行页面的榜单详情页以及歌手页面的歌手详情页,这里的排版布局模式和动画效果几乎都是一样的,不同的地方只有页面上方的标题,页面的背景图片和页面的数据列表,所以这个组件是可以复用的。只需要父组件在调用该子组件的时候将名称(name),背景图片(image),数据列表(list)三个参数传入即可。同时榜单列表里面有一个排行的位次,所以提前先在musicList组件里面写好相应的样式,并且在父组件调用的时候传入一个参数showNumber,为true的时候显示位次,为false的时候不显示。

  • scroll组件

由于移动端的滚动这里使用的是better-scroll插件,而每一次调用的时候都需要重新初始化一遍,这里是非常麻烦的。所以抽象出一个scroll组件,在组件内部使用slot插槽,在调用的时候,只需要将滚动的元素放在标签中间即可。由于该组件刚开始调用的时候可能还有一些异步获取的资源没有获取到,所以相应的dom元素还没有渲染出来,导致并不能正确的计算元素的高度, 所以传入一参数data,监听data的变化,当获取到数据以后调用refresh方法,重新计算元素的高度。同时在歌手页面中,需要歌手列表的滚动和右边字母索引相匹配,这里给scroll组件传入一个probeType参数为3,这样的话,scroll对象在滚动的时候就会监听scroll事件并且派发scroll事件,返回滚动的y值,通过y值就可以计算出滚动到什么位置,切换相应的字母索引。

  • player组件

播放器内核组件是代码最多,应用也最复杂的一个组件。该组件的渲染只与playlist的长度有关,并不受其他组件的影响,所以放在App.vue里面。背景图片使用相应的专辑图片并且宽高与屏幕高度一致,并且模糊处理(filter: blur(20px)),中间为一个具有旋转动画的专辑图片,向左滑动有可以滚动的歌词区。下方为进度条,可以通过点击或者是拖拽的方式改变播放进度。最下面是播放器的控制按钮。 该组件播放歌曲的原理是,在vuex中定义了playlist和currentIndex,通过在播放列表中的index值来确定播放的歌曲(currentSong),通过监听currentSong的变化,来给audio标签赋src值。

  • searchDetail组件

该组件的作用为展示搜索结果。该组件的设计思路为放置两个ul标签,第一个展示搜索到的歌手,第二个展示搜索到的歌曲。由于在添加歌曲页面,只搜索歌曲,并不搜索歌手,所以可以传入一个参数showZhida,来控制歌手的显示与隐藏。 在点击相应的歌手或者是歌曲的时候,该组件并不对数据做出处理,因为该组件在搜索页面和添加歌曲页面都有调用,但是作用却是不一样的。所以这里在进行点击以后只派发事件到父组件那里,告诉父组件有哪些元素被点击了, 由父组件来进行相应的歌手详情页的跳转和歌曲的播放或者是添加,这样就保证了该组件的独立性。

调用的库

  • better-scroll

better-scroll可以解决移动端的滚动问题。基本原理是需要一个父元素具有固定的高度,overflow属性为hidden。内部子元素高度超过父元素,better-scroll可以计算子元素的高度,通过设置transform,来使子元素发生滚动

  • vue-lazyload

vue-lazyload可以解决图片懒加载的问题。主要使用的组件是歌手组件,歌单组件和榜单组件,可以提升用户体验,减少浏览器的负载。基本原理是首先将图片的地址赋值为自己在初始化vueLazyLoad的时候使用的loading图片,将真实的图片地址保存在v-lazy属性中,通过观察图片的位置。 如果显示在浏览器的视口内,再将真实的图片地址赋值给图片。

  • jquery

在这里使用jquery主要的目的是因为jquery设置动画比较简便。在player组件中,由mini播放器扩大到全页面播放器,需要专辑图片位置上的移动和scale上的变化,而且是分段进行的,手写动画会很麻烦,所以这里使用$('').css来设置transform属性比较方便。

  • good-storage

这是一个对于localStorage方法的一个封装。主要用于保存搜索历史,喜爱的歌曲和听过的歌曲等数据。

  • lyric-parser

该库主要用于对于歌词的处理,该库返回一个Lyric类,初始化这个类的实例的时候将标准的歌词数据作为字符串传入,它可以自动添加一个计时器,同时有一个回调函数,该函数可以返回当前的歌词的行数和该行歌词的数据。用于使歌词发生滚动和当前歌词高亮显示。

  • jsonp

该库主要是为了获得qq音乐服务器的数据。jsonp是json的一种使用模式,它可以实现跨域读取数据。原理为该站脚本创建一个<script>标签,地址指向第三方的url,并提供一个callback函数来接收数据,第三方产生的响应为 json数据的包装,形如:callback({"": ""}),这样浏览器就可以对于里面的json数据做出处理了。

About

基于vue框架实现的web音乐app

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published