zoukankan      html  css  js  c++  java
  • Vue-music 项目学习笔记:播放器内置组件开发(一)

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

    一、播放器Vuex数据设计

    • 需求: 播放器可以通过歌手详情列表、歌单详情列表、排行榜、搜索结果多种组件打开,因此播放器数据一定是全局的

    • state.js目录下:定义数据

      import {playMode} from '@/common/js/config'
      
      const state = {
              singer: {},
              playing: false, //播放状态
              fullScreen: false, //播放器展开方式:全屏或收起
              playlist: [], //播放列表(随机模式下与顺序列表不同)
              sequenceList: [], //顺序播放列表
              mode: playMode.sequence, //播放模式: 顺序、循环、随机
              currentIndex: -1 //当前播放歌曲的index(当前播放歌曲为playlist[index])
      }
      
    • common->js目录下:创建config.js配置项目相关

      //播放器播放模式: 顺序、循环、随机
      export const playMode = {
             sequence: 0, 
             loop: 1,
             random: 2
      }
      
    • getter.js目录下:数据映射(类似于计算属性)

      export const playing = state => state.playing
      export const fullScreen = state => state.fullScreen
      export const playlist = state => state.playlist
      export const sequenceList = state => state.sequenceList
      export const mode = state => state.mode
      export const currentIndex = state => state.currentIndex
      
      export const currentSong = (state) => {
                return state.playlist[state.currentIndex] || {}
      }
      

      组件中可以通过mapgetters拿到这些数据

    • mutaion.js目录下:操作state

      const mutations = {
             [types.SET_SINGER](state, singer){
                   state.singer = singer
             },
             [types.SET_PLAYING_STATE](state, flag){
                   state.playing = flag
             },
             [types.SET_FULL_SCREEN](state, flag){
                   state.fullScreen = flag
             },
             [types.SET_PLAYLIST](state, list){
                   state.playlist = list
             },
             [types.SET_SEQUENCE_LIST](state, list){
                   state.sequenceList = list
             },
             [types.SET_PLAY_MODE](state, mode){
                   state.mode = mode
             },
             [types.SET_CURRENT_INDEX](state, index){
                   state.currentIndex = index
             }
      }
      

    二、播放器Vuex的相关应用

    • components->player目录下:创建player.vue

      基础DOM

      <div class="normal-player">
              播放器
      </div>
      <div class="mini-player"></div>
      
    • App.vue中应用player组件:因为它不是任何一个路由相关组件,而是应用相关播放器,切换路由不会影响播放器的播放

      <player></player>
      
    • player.vue中获取数据:控制播放器的显示隐藏

      import {mapGetters} from 'vuex'
      
      computed: {
            ...mapGetters([
                 'fullScreen',
                 'playlist'
            ])
      }
      

      通过v-show判断播放列表有内容时,显示播放器,依据fullScreen控制显示不同的播放器

    • song-list.vue中添加点击播放事件:基础组件不写业务逻辑,只派发事件并传递相关数据

      @click="selectItem(song, index)
      
      selectItem(item, index){
            this.$emit('select', item, index)
      }
      

      子组件行为,只依赖本身相关,不依赖外部调用组件的需求,传出的数据可以不都使用

    • music-list.vue中监听select事件

      <song-list :songs="songs" @select="selectItem"></song-list>
      
      • 设置数据,提交mutations:需要在一个动作中多次修改mutations,在actions.js中封装

        import * as types from './mutation-types'
        
        export const selectPlay = function ({commit, state}, {list, index}) {
                 //commit方法提交mutation
                 commit(types.SET_SEQUENCE_LIST, list)
                 commit(types.SET_PLAYLIST, list)
                 commit(types.SET_CURRENT_INDEX, index)
                 commit(types.SET_FULL_SCREEN, true)
                 commit(types.SET_PLAYING_STATE, true)
        }
        
      • music-list.vue中代理actions,并在methods中调用:

        import {mapActions} from 'vuex' 
        
        selectItem(item, index){
                this.selectPlay({
                     list: this.songs,
                     index
                })
        }
        ...mapActions([
                'selectPlay'
        ])
        

    三、播放器基础样式及歌曲数据的应用

    • 通过mapGetter获取到currentSong数据填入到DOM中:点击切换播放器展开收起,需要修改fullScreen
    import {mapGetters, mapMutations} from 'vuex'
    
    methods: {
         back() {
              //错误做法: this.fullScreen = false
              //正确做法: 通过mapMutations写入 
              this.setFullScreen(false)
         },
         open() {
              this.setFullScreen(true)
         },
         ...mapMutations({
              setFullScreen: 'SET_FULL_SCREEN'
         })
    }
    

    四、播放器展开收起动画

    • 需求:normal-player背景图片渐隐渐现,展开时头部标题从顶部下落,底部按钮从底部回弹,收起时相反

    • 实现:动画使用,回弹效果使用贝塞尔曲线

      • normal-player设置动画

        &.normal-enter-active, &.normal-leave-active
                 transition: all 0.4s
                 .top, .bottom
                      transition: all 0.4s cubic-bezier(0.86, 0.18, 0.82, 1.32)
        &.normal-enter, &.normal-leave-to
                 opacity: 0
                 .top
                      transform: translate3d(0, -100px, 0)
                 .bottom
                      transform: translate3d(0, 100px, 0)
        
      • mini-player设置动画

        &.mini-enter-active, &.mini-leave-active
              transition: all 0.4s
        &.mini-enter, &.mini-leave-to
              opacity: 0
        
    • 需求:展开时,mini-player的专辑图片从原始位置飞入CD图片位置,同时有一个放大缩小效果, 对应顶部和底部的回弹;收起时,normal-player的CD图片从原始位置直接落入mini-player的专辑图片位置

    • 实现:Vue提供了javascript事件钩子,在相关的钩子中定义CSS3动画即可

      • 利用第三方库:create-keyframe-animation 使用js编写CSS3动画

      • github地址:https://github.com/HenrikJoreteg/create-keyframe-animation

      • 安装:

        npm install create-keyframe-animation --save
        
      • 引入:

        import animations from 'create-keyframe-animation'
        
        <transition name="normal" @enter="enter" @after-enter="afterEnter" @leave="leave" @after-leave="afterLeave">
        
      • methods中封装函数_getPosAndScale获取初始位置及缩放尺寸: (计算以中心点为准)

        _getPosAndScale(){ 
               const targetWidth = 40 //mini-player icon宽度
               const width = window.innerWidth * 0.8 //cd-wrapper宽度
               const paddingLeft = 40 
               const paddingTop = 80
               const paddingBottom = 30 //mini-player icon中心距底部位置
               const scale = targetWidth / width
               const x = -(window.innerWidth / 2 - paddingLeft) //X轴方向移动的距离
               const y = window.innerHeight - paddingTop - width / 2 - paddingBottom
               return {
                     x,
                     y, 
                     scale
               }
        }
        
      • 定义事件钩子方法:

        //事件钩子:创建CSS3动画
        enter(el, done){
                const {x, y, scale} = this._getPosAndScale()
        
                let animation = {
                       0: {
                          transform: `translate3d(${x}px, ${y}px, 0) scale(${scale})`
                       },
                       60: {
                          transform: `translate3d(0, 0, 0) scale(1.1)`
                       }, 
                       100: {
                          transform: `translate3d(0, 0, 0) scale(1)`
                       }
                }
        
                animations.registerAnimation({
                       name: 'move',
                       animation,
                       presets: {
                          duration: 400,
                          easing: 'linear'
                       }
                })
        
               animations.runAnimation(this.$refs.cdWrapper, 'move', done)
        },
        afterEnter() {
               animations.unregisterAnimation('move')
               this.$refs.cdWrapper.style.animation = ''
        },
        leave(el, done){
               this.$refs.cdWrapper.style.transition = 'all 0.4s'
               const {x, y, scale} = this._getPosAndScale()
               this.$refs.cdWrapper.style[transform] = `translate3d(${x}px, ${y}px, 0) scale(${scale})`
               this.$refs.cdWrapper.addEventListener('transitionend', done)
        },
        afterLeave(){
               this.$refs.cdWrapper.style.transition = ''
               this.$refs.cdWrapper.style[transform] = ''
        }
        
      • transform属性使用prefix自动添加前缀:

        import {prefixStyle} from '@/common/js/dom'
        const transform = prefixStyle('transform')
        
  • 相关阅读:
    html5 td中的5它空隙待解决
    转:能说明你的Javascript技术很烂的五个原因
    css字体中文、英文、Unicode名对照表
    相对定位一个例子,仿淘宝商品列表中的简单效果
    利用Javascript判断操作系统的类型
    百度web前端面试题之求两个数的最大公约数和最小公倍数
    程序员在群询问破解软件
    转:IE10初探
    学习js在线html(富文本)编辑器
    json学习笔记
  • 原文地址:https://www.cnblogs.com/zlv2snote/p/10433015.html
Copyright © 2011-2022 走看看