前言:以下内容均为学习慕课网高级实战课程的实践爬坑笔记。
项目github地址:https://github.com/66Web/ljq_vue_music,欢迎Star。
歌曲列表 收藏歌曲
一、用户个人中心开发
基础功能开发
设置路由跳转
在components->user-center目录下:创建user-center.vue
router->index.js中配置路由:
{
path: ‘/user’,
component: UserCenter
}
m-header.vue中通过实现跳转
应用Switches组件
引用注册并使用
<switches @switch=“switchItem” :switches=“switches”
:currentIndex=“currentIndex”>
定义data数据绑定
data() {
return {
currentIndex: 0,
switches: [
{name: ‘我喜欢的’},
{name: ‘最近听的’}
]
}
}
定义方法将获得的index赋值给currentIndex
switchItem(index) {
this.currentIndex = index
}
返回上一级路由
给按钮添加点击事件
@click=“back”
定义方法通过router.back返回
back(){
this.$router.back() //回退到上一级路由
}
收藏列表开发
Vuex数据配置
states.js中:添加数据
favoriteList: []
mutation-types.js中:定义事件类型常量
export const SET_FAVORITE_LIST = ‘SET_FAVORITE_LIST’
mutations.js中:定义修改方法
[types.SET_FAVORITE_LIST](state, list){
state.favoriteList = list
}
getters.js中:设置数据映射
export const favoriteList = state => state.favoriteList
catch.js中操作storage
定义本地缓存的Key和最大存储歌曲值
const FAVORITE_KEY = ‘favorite’
const FAVORITE_MAX_LENGTH = 200
保存歌曲到本地缓存
export function saveFavorite(song) {
let songs = storage.get(FAVORITE_KEY, [])
insertArray(songs, song, (item) => {
return song.id === item.id
}, FAVORITE_MAX_LENGTH)
storage.set(FAVORITE_KEY, songs)
return songs
}
从本地缓存中删除歌曲
export function deleteFavorite(song) {
let songs = storage.get(FAVORITE_KEY, [])
deleteFromArray(songs, (item) => {
return song.id === item.id
})
storage.set(FAVORITE_KEY, songs)
return songs
}
从本地缓存中获取全部歌曲
export function loadFavorite() {
return storage.get(FAVORITE_KEY, [])
}
actions.js中:封装方法
同时保存到Vuex和本地缓存
export const saveFavoriteList = function ({commit}, song) {
commit(types.SET_FAVORITE_LIST, saveFavorite(song))
}
同时从Vuex和本地缓存删除
export const deleteFavoriteList = function ({commit}, song) {
commit(types.SET_FAVORITE_LIST, deleteFavorite(song))
}
states.js中修改初始数据为本地缓存数据
favoriteList: loadFavorite()
player.vue中修改按钮,动态绑定class,监听点击事件
<i class=“icon” @click=“toggleFavorite(currentSong)”
:class=“getFavoriteIcon(currentSong)”>
mixin.js中在playerMixin中添加收藏歌曲需要的共享逻辑
通过mapGetters获得已收藏的歌曲数据:‘favoriteList’
抽象出一个方法判断所选歌曲是否在已收藏的歌曲数据中
isFavorite(song){
const index = this.favoriteList.findIndex((item) => {
return item.id === song.id
})
return index > -1 //如果index > -1 isFavorite 返回true
}
定义方法依据所选歌曲是否为已收藏的歌曲,取反改变icon样式
getFavoriteIcon(song){
if(this.isFavorite(song)){
return ‘icon-favorite’
}
return ‘icon-not-favorite’
}
定义方法调用通过mapActions引用的action,同上取反进行保存或删除
toggleFavorite(song){
if(this.isFavorite(song)){
this.deleteFavoriteList(song)
}else{
this.saveFavoriteList(song)
}
}
playlist.vue中添加数据映射和点击事件
<span class=“like” @click.stop=“toggleFavorite(item)”>
usercenter.vue中渲染收藏列表和播放历史列表
布局DOM: 同add-song.vue
<song-list :songs=“favoriteList” @select=“selectSong”>
<song-list :songs=“playHistory” @select=“selectSong”>
通过mapGetters获取收藏歌曲数据和播放历史数据
computed: {
…mapGetters([
‘favoriteList’,
‘playHistory’
])
}
定义方法,调用通过mapActions获取到的insertSong方法,将song实例化之后插入
selectSong(song) {
this.insertSong(new Song(song))
},
…mapActions([
‘insertSong’
])
剩余功能开发
随机播放全部功能实现
给按钮添加点击事件,通过mapActions获取到randomPlay方法
mixins:[playlistMixin],
handlePlaylist(playlist){
const bottom = playlist.length > 0 ? ‘60px’ : ‘’
this.
r
e
f
s
.
l
i
s
t
W
r
a
p
p
e
r
.
s
t
y
l
e
.
b
o
t
t
o
m
=
b
o
t
t
o
m
/
/
判
断
列
表
D
O
M
存
在
后
再
执
行
r
e
f
r
e
s
h
t
h
i
s
.
refs.listWrapper.style.bottom = bottom //判断列表DOM存在后再执行refresh this.
refs.listWrapper.style.bottom=bottom//判断列表DOM存在后再执行refreshthis.refs.favoriteList && this.
r
e
f
s
.
f
a
v
o
r
i
t
e
L
i
s
t
.
r
e
f
r
e
s
h
(
)
t
h
i
s
.
refs.favoriteList.refresh() this.
refs.favoriteList.refresh()this.refs.playList && this.$refs.playList.refresh()
}
no-result组件的应用
布局DOM:
②事件play – 当音频/视频已开始或不再暂停时
注: 这里添加clearTimeout(this.timer)时总报timeout.close is not function,top-tip中使用过清理timer,没有问题,这里就不知道为什么了,待解决!
坑:快速切换歌曲时,歌词的播放异常
原因:异步时机问题 – setTImeout执行1s的操作中play()是一个同步的动作,而getLyric()是异步的操作;在异步获得回调时,有可能又切换到了下一首歌,这时之前的歌会在new一次,相当于new了两次,会有多个歌词同时存在
解决:在异步获得回调后先判断currentSong.lyric是否改变了,如果改变了不为layric,不执行任何操作
if(this.currentSong.lyric !== lyric){
return
}
坑:当前歌曲只有一首歌时,切换下一首,不会再触发ready()了
原因:next()中当列表长度为1时,会调用loop(),后面的ready标志位会一直为false,redy()也就不会再触发了
解决:在next()和prev()中,如果调用了loop()就直接return,不再修改标志位为false
三、项目打包及VConsole的使用
编译打包
npm run build
VConsole的使用
安装
在页面引入一个JS文件:下载地址
使用npm安装
npm install vconsole
使用webpack,然后在js代码中应用VConsole
import VConsole from ‘vconsole/dist/vconsole.min.js’ //引入vconsole
let vConsole = new VConsole() // 初始化
或者找到这个模块下面的 dist/vconsole.min.js ,然后复制到自己的项目中