前言:以下内容均为学习慕课网高级实战课程的实践爬坑笔记。

项目github地址:https://github.com/66Web/ljq_vue_music,欢迎Star。


歌曲列表 收藏歌曲
一、用户个人中心开发

基础功能开发

  • 设置路由跳转
  1. 在components->user-center目录下:创建user-center.vue
  2. router->index.js中配置路由:
    {
    path: '/user',
    component: UserCenter
    }
  3. m-header.vue中通过<router-link>实现跳转
    <router-link tp="/user" class="mine" tag="div">
    <i class="icon-mine"></i>
    </router-link>
  • 应用Switches组件
  1. 引用注册并使用

    <switches @switch="switchItem" :switches="switches"
    :currentIndex="currentIndex"></switches>
  2. 定义data数据绑定
    data() {
    return {
    currentIndex: 0,
    switches: [
    {name: '我喜欢的'},
    {name: '最近听的'}
    ]
    }
    }
  3. 定义方法将获得的index赋值给currentIndex
    switchItem(index) {
    this.currentIndex = index
    }
  • 返回上一级路由
  1. 给按钮添加点击事件

    @click="back"
  2. 定义方法通过router.back返回
    back(){
    this.$router.back() //回退到上一级路由
    }

收藏列表开发

  • Vuex数据配置
  1. states.js中:添加数据

    favoriteList: []
  2. mutation-types.js中:定义事件类型常量
    export const SET_FAVORITE_LIST = 'SET_FAVORITE_LIST'
  3. mutations.js中:定义修改方法
    [types.SET_FAVORITE_LIST](state, list){
    state.favoriteList = list
    }
  4. getters.js中:设置数据映射
    export const favoriteList = state => state.favoriteList
  • catch.js中操作storage
  1. 定义本地缓存的Key和最大存储歌曲值

    const FAVORITE_KEY = '_favorite_'
    const FAVORITE_MAX_LENGTH = 200
  2. 保存歌曲到本地缓存
    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
    }
  3. 从本地缓存中删除歌曲
    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
    }
  4. 从本地缓存中获取全部歌曲
    export function loadFavorite() {
    return storage.get(FAVORITE_KEY, [])
    }
  • actions.js中:封装方法
  1. 同时保存到Vuex和本地缓存

    export const saveFavoriteList = function ({commit}, song) {
    commit(types.SET_FAVORITE_LIST, saveFavorite(song))
    }
  2. 同时从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中添加收藏歌曲需要的共享逻辑
  1. 通过mapGetters获得已收藏的歌曲数据:'favoriteList'
  2. 抽象出一个方法判断所选歌曲是否在已收藏的歌曲数据中
    isFavorite(song){
    const index = this.favoriteList.findIndex((item) => {
    return item.id === song.id
    })
    return index > -1 //如果index > -1 isFavorite 返回true
    }
  3. 定义方法依据所选歌曲是否为已收藏的歌曲,取反改变icon样式
    getFavoriteIcon(song){
    if(this.isFavorite(song)){
    return 'icon-favorite'
    }
    return 'icon-not-favorite'
    }
  4. 定义方法调用通过mapActions引用的action,同上取反进行保存或删除
    toggleFavorite(song){
    if(this.isFavorite(song)){
    this.deleteFavoriteList(song)
    }else{
    this.saveFavoriteList(song)
    }
    }
  • playlist.vue中添加数据映射和点击事件

    <span class="like" @click.stop="toggleFavorite(item)">
    <i :class="getFavoriteIcon(item)"></i>
    </span>
  • usercenter.vue中渲染收藏列表和播放历史列表
  1. 布局DOM: 同add-song.vue

    <scroll ref="favoriteList" class="list-scroll" v-if="currentIndex===0"
    :data="favoriteList">
    <div class="list-inner">
    <song-list :songs="favoriteList" @select="selectSong"></song-list>
    </div>
    </scroll>
    <scroll ref="playList" class="list-scroll" v-if="currentIndex===1"
    :data="playHistory">
    <div class="list-inner">
    <song-list :songs="playHistory" @select="selectSong"></song-list>
    </div>
    </scroll>
  2. 通过mapGetters获取收藏歌曲数据和播放历史数据
    computed: {
    ...mapGetters([
    'favoriteList',
    'playHistory'
    ])
    }
  3. 定义方法,调用通过mapActions获取到的insertSong方法,将song实例化之后插入
    selectSong(song) {
    this.insertSong(new Song(song))
    },
    ...mapActions([
    'insertSong'
    ])

剩余功能开发

  • 随机播放全部功能实现
  1. 给按钮添加点击事件,通过mapActions获取到randomPlay方法

    <div ref="playBtn" class="play-btn" @click="random">
  2. 定义方法,判断currentIndex获取对应list,通过实例化处理传入action
    random(){
    let list = this.currentIndex === 0 ? this.favoriteList : this.playHistory
    //这时list还不是实例,需要遍历list进行实例化
    list = list.map((song) => {
    return new Song(song)
    })
    this.randomPlay({
    list
    })
    }
  • 播放器底部自适应

    import {playlistMixin} from '@/common/js/mixin'
    
    mixins:[playlistMixin],
    
    handlePlaylist(playlist){
    const bottom = playlist.length > 0 ? '60px' : ''
    this.$refs.listWrapper.style.bottom = bottom
    //判断列表DOM存在后再执行refresh
    this.$refs.favoriteList && this.$refs.favoriteList.refresh()
    this.$refs.playList && this.$refs.playList.refresh()
    }
  • no-result组件的应用
  1. 布局DOM:

    <div class="no-result-wrapper" v-if="noResult">
    <no-result :title="noResultDesc"></no-result>
    </div>
  2. 显示条件和显示提示内容都需要动态绑定计算属性,判断currentIndex
    noResult() {
    if(this.currentIndex === 0) {
    return !this.favoriteList.length
    }else{
    return !this.playHistory.length
    }
    },
    noResultDesc() {
    if(this.currentIndex === 0) {
    return '暂无收藏歌曲'
    }else{
    return '你还没有听过歌曲'
    }
    }
  3. 优化:当列表中无数据,点击随机播放全部时,rendom()不执行任何操作
    if(list.length === 0) {
    return
    }
二、性能优化
  • 坑:快速的点击播放暂停歌曲,发现歌曲和歌词还在播放
  1. 原因:player.vue中watch currentSong会做一些清理操作,并在1s内开启play()播放;此时如果很快的切换歌曲切换播放状态,调用ready()和watch playing中的pause()会在1s内执行完;虽然看起来pause执行了,但1s过去之后,又会重新开启play()
  2. 解决:在每次setTimeout前清理掉旧的timer,保证只有一个timer;同时修改ready的触发事件为play,保证ready()和pause()一定发生在play()后
  3. 区别:

    ①事件canplay -- 当浏览器可以播放音频/视频时

    ②事件play -- 当音频/视频已开始或不再暂停时

  4. 注: 这里添加clearTimeout(this.timer)时总报timeout.close is not function,top-tip中使用过清理timer,没有问题,这里就不知道为什么了,待解决!
  • 坑:快速切换歌曲时,歌词的播放异常
  1. 原因:异步时机问题 -- setTImeout执行1s的操作中play()是一个同步的动作,而getLyric()是异步的操作;在异步获得回调时,有可能又切换到了下一首歌,这时之前的歌会在new一次,相当于new了两次,会有多个歌词同时存在
  2. 解决:在异步获得回调后先判断currentSong.lyric是否改变了,如果改变了不为layric,不执行任何操作
    if(this.currentSong.lyric !== lyric){
    return
    }
  • 坑:当前歌曲只有一首歌时,切换下一首,不会再触发ready()了
  1. 原因:next()中当列表长度为1时,会调用loop(),后面的ready标志位会一直为false,redy()也就不会再触发了
  2. 解决:在next()和prev()中,如果调用了loop()就直接return,不再修改标志位为false
三、项目打包及VConsole的使用

       编译打包 

npm run build

       VConsole的使用  

  • 安装
  1. 在页面引入一个JS文件:下载地址
  2. 使用npm安装
    npm install vconsole
  • 使用webpack,然后在js代码中应用VConsole

    import VConsole from 'vconsole/dist/vconsole.min.js' //引入vconsole
    let vConsole = new VConsole() // 初始化

    或者找到这个模块下面的 dist/vconsole.min.js ,然后复制到自己的项目中

    <head>
    <script src="dist/vconsole.min.js"></script>
    </head>
    <!--建议在 `<head>` 中引入哦~ -->
    <script>
    // 初始化
    var vConsole = new VConsole();
    console.log('VConsole is cool');
    </script>

注:项目来自慕课网

【音乐App】—— Vue-music 项目学习笔记:用户个人中心开发的更多相关文章

  1. 【音乐App】—— Vue-music 项目学习笔记:推荐页面开发

    前言:以下内容均为学习慕课网高级实战课程的实践爬坑笔记. 上一篇总结了项目概述.项目准备.页面骨架搭建.这一篇重点梳理推荐页面开发.项目github地址:https://github.com/66We ...

  2. 【音乐App】—— Vue-music 项目学习笔记:搜索页面开发

    前言:以下内容均为学习慕课网高级实战课程的实践爬坑笔记. 项目github地址:https://github.com/66Web/ljq_vue_music,欢迎Star. 搜索歌手歌曲 搜索历史保存 ...

  3. 【音乐App】—— Vue-music 项目学习笔记:歌手页面开发

    前言:以下内容均为学习慕课网高级实战课程的实践爬坑笔记. 项目github地址:https://github.com/66Web/ljq_vue_music,欢迎Star. 一.歌手页面布局与设计 需 ...

  4. 【音乐App】—— Vue-music 项目学习笔记:项目准备

    前言: 学习慕课网Vue高级实战课程后,在实践中总结一些这个项目带给自己的收获,希望可以再次巩固关于Vue开发的知识.这一篇主要梳理:项目概况.项目准备.页面骨架搭建.项目github地址:https ...

  5. 【音乐App】—— Vue-music 项目学习笔记:歌单及排行榜开发

    前言:以下内容均为学习慕课网高级实战课程的实践爬坑笔记. 项目github地址:https://github.com/66Web/ljq_vue_music,欢迎Star. 歌单及详情页 排行榜及详情 ...

  6. 【音乐App】—— Vue-music 项目学习笔记:歌手详情页开发

    前言:以下内容均为学习慕课网高级实战课程的实践爬坑笔记. 项目github地址:https://github.com/66Web/ljq_vue_music,欢迎Star. 歌曲列表 歌曲播放 一.子 ...

  7. 【音乐App】—— Vue-music 项目学习笔记:播放器内置组件开发(二)

    前言:以下内容均为学习慕课网高级实战课程的实践爬坑笔记. 项目github地址:https://github.com/66Web/ljq_vue_music,欢迎Star. 播放模式切换 歌词滚动显示 ...

  8. 【音乐App】—— Vue-music 项目学习笔记:歌曲列表组件开发

    前言:以下内容均为学习慕课网高级实战课程的实践爬坑笔记. 项目github地址:https://github.com/66Web/ljq_vue_music,欢迎Star. 当前歌曲播放列表 添加歌曲 ...

  9. 最新 Vue 源码学习笔记

    最新 Vue 源码学习笔记 v2.x.x & v3.x.x 框架架构 核心算法 设计模式 编码风格 项目结构 为什么出现 解决了什么问题 有哪些应用场景 v2.x.x & v3.x.x ...

随机推荐

  1. 在线人数统计session管理

    下午比较闲(其实今天都很闲),想了一下在线人数统计方面的实现,上网找了下这方面的知识,最初我的想法是,管理session,如果session销毁了就减少,如果登陆用户了就新增一个,但是如果是用户非法退 ...

  2. ansible中playbook使用

    palybook使用 ####yaml语法ansible中使用的yaml基础元素:变量Inventory条件测试迭代 playbook的组成结构InventoryModulesAd Hoc Comma ...

  3. ubuntu--基础环境瞎搞集合

    安装ubuntu系统后有很多东西需要自己瞎搞一下,这里把一些瞎搞的过程记录在这里,方便以后重新装系统后重新配置. 一.安装. 可以在windows下制作启动盘(软碟通),然后开机u盘启动即可安装,预留 ...

  4. Markdown语法图解

    Markdown语法图解 文章目录 快捷键 基本语法 对字体设置斜体.粗体.删除线 分级标题 链接 分割线 代码块 引用 列表 表格 常用技巧 换行 缩进字符 如何打出一些特殊符号 字体.字号与颜色 ...

  5. [HAOI2010][bzoj2424] 订货 [费用流]

    题面 传送门 思路 这题其实挺水的......做过餐巾计划问题就能明白,是同一个道理 首先,显然刚刚好满足每一个月的需求,会得到最优解(废话-_-||) 然后我们发现,货物在不同的月之间的转移,可以比 ...

  6. 剑指offer42:翻转单词顺序 VS 左旋转字符串(更高效、简便的解法)

    题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变.为简单起见,标点符号和普通字母一样处理.例如输入字符串"I am a student." ,则输出" ...

  7. redis学习(五)事务

    事务是一个单独的隔离操作:事务中的所有命令都会序列化.按顺序地执行.事务在执行的过程中,不会被其他客户端发送来的命令请求所打断. 1.事务基本命令: multi:标记一个事务块的开始 exec:执行所 ...

  8. 【最大流】hihocoder 1369 : 网络流一·Ford-Fulkerson算法

    http://hihocoder.com/problemset/problem/1369?sid=1328132 参考 https://blog.csdn.net/a1799342217/articl ...

  9. 初识laytpl

    laytpl-精致巧妙的JavaScript模板引擎 这两天在做一个mui项目,列表需要循环很多的数据.在公司同事的指引下认识了这个新的模板--laytpl.我只想说,很好用们很巧妙. 废话不多说,直 ...

  10. .net web api返回结果为json

    web api写api接口时默认返回的是把你的对象序列化后以XML形式返回,那么怎样才能让其返回为json呢,下面为大家介绍几种不错的方法 web api写api接口时默认返回的是把你的对象序列化后以 ...