一、路由切换过渡效果
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'
])