歌手详情页(2)

一、路由切换过渡效果

vue.js内部组件实现组件进入和离开的过渡效果,原理:使用transitions组件之后,在合适的时机给dom元素添加样式

全局定义过渡效果

translate3d横向坐标偏移百分百,偏移一个身位

.slide-enter-active, .slide-leave-active {
  transition: all 0.3s
}

.slide-enter-from, .slide-leave-to {
  transform: translate3d(100%, 0, 0)
}

路由切换地方添加api

appear:进入时就添加动画效果

<router-view v-slot="{ Component }">
      <transition appear name="slide">
        <component :is="Component" :data="selectedSinger"/>
      </transition>
    </router-view>

二、边界情况处理

获取不到数据时候的情况,当没有数据时候渲染不同的画面

编写no-result组件,将loading组件抽象出来,封装函数createLoadingLikeDirective传入no-result组件

import { createApp } from 'vue'
import { addClass, removeClass } from '@/assets/js/dom'

const relativeCls = 'g-relative'

export default function createLoadingLikeDirective(Comp) {
    return {
        mounted(el, binding) {
            const app = createApp(Comp)
            const instance = app.mount(document.createElement('div'))
            const name = Comp.name
            if (!el[name]) {
                el[name] = {}
            }
            el[name].instance = instance
            const title = binding.arg
            if (typeof title !== 'undefined') {
                instance.setTitle(title)
            }
    
            if (binding.value) {
                append(el)
            }
        },
        updated(el, binding) {
            const title = binding.arg
            const name = Comp.name
            if (typeof title !== 'undefined') {
                el[name].instance.setTitle(title) 
            }
            if (binding.value !== binding.oldValue) {
                binding.value ? append(el) : remove(el)
            }
        }
    }

    function append(el) {
        const name = Comp.name
        const style = getComputedStyle(el)
        if(['absolute', 'fixed', 'relative'].indexOf(style.position) === -1) {
            addClass(el, relativeCls)
        }
        el.appendChild(el[name].instance.$el)
    }
    
    function remove(el) {
        const name = Comp.name
        removeClass(el, relativeCls)
        el.removeChild(el[name].instance.$el)
    }
}

使用函数创造指令

import Loading from './loading'
import createLoadingLikeDirective from '@/assets/js/create-loading-like-directive'

const loadingDirective = createLoadingLikeDirective(Loading)

export default loadingDirective
import NoResult from './no-result'
import createLoadingLikeDirective from '@/assets/js/create-loading-like-directive'

const noResultDirective = createLoadingLikeDirective(NoResult)

export default noResultDirective

创造指令后注册指令

import noResultDirective from './components/base/no-result/directive'


createApp(App).use(store).use(router).use(lazyPlugin,{
    loading: require('@/assets/images/default.png')
}).directive('loading', loadingDirective).directive('no-result', noResultDirective).mount('#app')

使用指令

v-no-result:[noResultText]="noResult"

定义noResult,当loading结束之后且songs.length为空时才会显示

noResult() {
        return !this.loading && !this.songs.length
      },

错误:两个指令都作用到同一元素,后面覆盖前面
解决:根据传递的Comp组件不同,组件的name不同,绑定到el的name上(多加一位)代码上面已做修改

没有数据的文案定义在props
方便修改

三、歌曲列表点击和vuex的应用

Vuex:全局状态管理的工具

State:全局数据仓库,存储最基础的数据
Getters:State的计算属性,基于多个State可以计算出新的数据
Mutations:对State做改变,唯一可以改变数据的途径
Actions:对Mutations的封装

拆分到不同的文件中

顺序播放列表 sequenceList,正在播放列表 playlist,
播放状态 playing,播放模式 playMode ,
顺序播放 sequence,循环播放 loop,随机播放 random,
当前播放索引 currentIndex,播放器状态 fullScreen

state.js

import { PLAY_MODE } from "@/assets/js/constant"

const state = {
    sequencelList: [],
    playlist: [],
    playing: false,
    playMode: PLAY_MODE.sqeuence,
    currentIndex: 0,
    fullScreen: false
}

export default state

getters.js

通过播放列表以及当前播放的索引来计算当前播放的歌曲是什么

export const currentSong = (state) => {
    return state.playlist[state.currentIndex]
}

mutations.js

对原始数据修改

const mutations = {
    setPlayingState(state, playing) {
        state.playing = playing
    },
    setSequenceList(state, list) {
        state.sequenceList = list
    },
    setPlayList(state, list) {
        state.playlist = list
    },
    setPlayMode(state, mode) {
        state.playMode = mode
    },
    setCurrentIndex(state, index) {
        state.currentIndex = index
    },
    setFullScreen(state, fullScreen) {
        state.fullScreen = fullScreen
    }
}

export default mutations

actions.js
定义dom,选择播放

import { PLAY_MODE } from "@/assets/js/constant";

export function selectPlay({ commit }, { list, index }) {
    commit('setPlayMode', PLAY_MODE.sqeuence)
    commit('setSequenceList', list)
    commit('setPlayingState', true)
    commit('setFullScreen', true)
    commit('setPlaylist', list)
    commit('setCurrentIndex', index)
}

index.js
开发环境(debug环境)下用createLogger插件查看提交状态

import { createStore, createLogger } from 'vuex'
import state from './state'
import mutations from './mutations'
import * as getters from './getters'
import * as actions from './actions'

const debug = process.env.NODE_ENV !== 'production'

export default createStore({
  state,
  getters,
  mutations,
  actions,
  strict: debug,
  plugins: debug ? [createLogger()] : []
})

绑定click事件 song-list.vue

遍历拿到索引,传出索引

		v-for="(song, index) in songs"
        @click="selectItem(song, index)"

定义事件 派发select事件

selectItem(song, index) {
          this.$emit('select', { song, index })
        },

监听click事件 music-list.vue

派发action,使用vuex提供的语法

  import { mapActions, mapState } from 'vuex'
selectItem({ song, index }) {
        this.selectPlay({
          list: this.songs,
          index
        })
      }...mapActions([
        'selectPlay',
        'randomPlay'
      ])
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值