目录
(2)页面一进来数据还没加载完播放按钮没数据播放(MusicList.vue)
(3)加载数据的加载动画(SingerDetail.vue)
1、解决用滚动组件的问题
问题:使用滚动组件只给了bottom的值,未给top值,所以无法计算,以至于滚动组件失效。
(要计算背景图片的高度)
通过ref 获取元素
<!-- 封面背景图 -->
<div class="bg-image" :style="bgImageStyle" ref="imageRef"></div>
const imageHeight = ref(0);
const imageRef = ref(null);
onMounted(() => {
// 获取一下封面背景图div的高度
imageHeight.value = imageRef.value.clientHeight;
});
MusicList:然后给scroll动态绑定一个style
<!-- 歌曲列表 -->
<my-scroll class="list" :probeType="3" :style="scrollStyle">
<div class="song-list-wrapper">
<my-songList :songs="songs"></my-songList>
</div>
</my-scroll>
const scrollStyle = computed(() => {
return {
top: `${imageHeight.value}px`,
}
})
设置当前滚动区域的边界
const maxTranslateY = ref(0);
onMounted(() => {
maxTranslateY.value = imageHeight.value - 40;
});
绑定自定义事件@scroll
<!-- 歌曲列表 -->
<my-scroll class="list" :probeType="3" :style="scrollStyle" @scroll="onScroll">
<div class="song-list-wrapper">
<my-songList :songs="songs"></my-songList>
</div>
</my-scroll>
打印鼠标滑动的值
const scrollY = ref(0);
function onScroll(pos) {
// 打印鼠标滑动的值
console.log(pos);
scrollY.value = -pos.y;
}
实时监听
const bgImageStyle = computed(() => {
// 实时监听
let height = "40%";
let zIndex = 0;
if(scrollY.value > maxTranslateY.value) {
// 触发滚动临界
height = "40px";
zIndex = 1;
}
return {
backgroundImage: `url(${props.picUrl})`,
height,
zIndex
};
});
当到了滚动临界是播放按钮应该隐藏起来,给播放按钮绑定一个样式
<div class="play-btn-wrapper" :style="playBtnStyle">
<div class="play-btn">
<i class="icon-play"></i>
<span class="text">顺序播放全部</span>
</div>
</div>
const playBtnStyle = computed(() => {
let display = "block";
if(scrollY.value > maxTranslateY.value) {
display = "none";
}
return {
display,
}
})
上拉时给背景图一个模糊遮罩的效果(css滤镜:backdrop-filter的blur())先绑定一下样式
<!-- 模糊遮罩 -->
<div class="filter" :style="filterStyle"></div>
const filterStyle = computed(() => {
let blur = 0;
if(scrollY.value > 0) {
//限制了一下访问以至于不会太模糊
blur = Math.min(scrollY.value / 25, 10);
}
return {
backdropFilter: `blur(${blur}px`,
}
})
下拉时背景放大
const bgImageStyle = computed(() => {
// 实时监听
let height = "40%";
let zIndex = 0;
let scale = 1;
if (scrollY.value > maxTranslateY.value) {
// 触发滚动临界
height = "40px";
zIndex = 1;
}
// 下拉列表时放大
if(scrollY.value < 0) {
// 往下拉了多少bgImage,就放大多少transform:scale(1+???)
// scrollY.value = bgImage放大的量 = (???) * bgImage原本的高度
// (???) = scrollY.value / bgImage原本的高度
// 放大的值 = 1 + (???)
scale = -scrollY.value / imageHeight.value + 1;
}
return {
backgroundImage: `url(${props.picUrl})`,
height,
zIndex,
Transform: `scale(${scale})`
};
});
2、bug解决及优化
(1)当前页面刷新会报错:没有路由参数就拿不到数据![](https://img-blog.csdnimg.cn/7a79385ddb08493890dd15dae983e19d.png)
在Singer.vue页面中加上一个本地存储
function getSinger(item) {
// console.log(item);
singerDetail.value = {
picUrl: item.picUrl,
id: item.id,
name: item.name
};
// 本地存储
myStorage.setLocal("__singerDetail__",singerDetail.value);
// 路由跳转
router.push({
path: `/singer/${item.id}`,
})
}
在SingerDetail.vue中导入
import myStorage from "@/assets/js/storage-api";
import { useRoute } from "vue-router";
const route = useRoute();
const computedData = computed(() => {
let result = null;
const data = props.detailObj;
if (data.id) {
// props获取成功
result = data;
} else {
//props获取失败
const cached = myStorage.getLocal("__singerDetail__");
// 存储的值cached存在的话,并且cached的id和路由上的id保持一致
//除一个1让字符串转化为number类型
if (cached && cached.id === route.params.id / 1) {
result = cached;
}
}
return result;
});
优化刷新页面无数据返回上一级
import { useRoute, useRouter } from "vue-router";
const router = useRouter();
// 背景图片
const picUrl = computed(() => {
return computedData.value ? computedData.value.picUrl : "";
});
// 标题
const listTitle = computed(() => {
return computedData.value ? computedData.value.name : "";
});
onMounted(async () => {
const data = computedData.value;
//props内和本地存储内都没有数据
if (!data) {
// 跳转回当前路由的上一级路由
router.push({ path: route.matched[0].path });
return;
}
// console.log(props.detailObj);
// const result = await getSingerDetail(props.detailObj);
const result = await getSingerDetail(data);
console.log(result);
songs.value = result.hotSongs;
// console.log(songs.value);
});
(2)页面一进来数据还没加载完播放按钮没数据播放(MusicList.vue)
<div class="play-btn" v-show="songs.length > 0">
<i class="icon-play"></i>
<span class="text">顺序播放全部</span>
</div>
(3)加载数据的加载动画(SingerDetail.vue)
先传入loading
<template>
<div class="singer-detail">
<my-musicList :loading="loading" :picUrl="picUrl" :listTitle="listTitle" :songs="songs"
></my-musicList>
</div>
</template>
const loading = ref(true);
onMounted(async () => {
const data = computedData.value;
//props内和本地存储内都没有数据
if (!data) {
// 跳转回当前路由的上一级路由
router.push({ path: route.matched[0].path });
return;
}
const result = await getSingerDetail(data);
console.log(result);
songs.value = result.hotSongs;
loading.value = false;
});
在MusicList.vue接收一下loading
const props = defineProps({
loading: Boolean,
});
<div class="song-list-wrapper" v-loading="loading">
<my-songList :songs="songs"></my-songList>
</div>
(4)返回按钮
在MusicList.vue中导入vue-router
import {useRouter} from "vue-router";
// 调用
const router = useRouter();
// 返回上一级
function goBack() {
router.go(-1);
}
绑定给返回上一级的按钮
<!-- 返回按钮 -->
<div class="back" @click="goBack">
<i class="icon-back"></i>
</div>
(5)点击切换优化滑动过渡效果
问题使用vue2写法会警告
<transition>
<router-view :detailObj="singerDetail"></router-view>
</transition>
vue3的写法就在警告里
<router-view v-slot="{ Component }">
<transition name="slide" appear>
<component :is="Component" :detailObj="singerDetail" />
</transition>
</router-view>
3、vueX
全局共享数据(将store文件夹下index.js中抽离出来)
state.js
const state = {
//当前播放歌曲的列表
sequenceList: [],
// 源播放列表
playlist: [],
// 播放状态
playing: false,
// 播放模式:0顺序播放 1单曲循环 2随机播放
playmode: 0,
// 当前播放歌曲的索引值
currentIndex: 0,
// 全屏播放器/迷你播放器
fullScreen: false,
// 最爱的歌曲列表
favoriteList: [],
// 历史播放记录
playHistory: []
}
// 导出
export default state
getters.js
const getters = {
// 获取当前播放歌曲对象
currentSong(state) {
return state.sequenceList[state.currentIndex] || {}
}
}
export default getters
mutation.js
import getters from "./getters"
const mutations = {
// 设置当前歌曲列表
setSequenceList(state, list) {
state.sequenceList = list
},
// 设置源歌曲列表
setPlayList(state,list) {
state.playList = list
},
// 设置播放状态
setPlayingState(state, playing) {
state.playing = playing
},
// 设置播放模式
setPlayMode(state, mode) {
state.playMode = mode
},
// 设置播放索引值
setCurrentIndex(state, index) {
state.currentIndex = index
},
// 设置全屏状态
setFullScreen(state, fullScreen) {
state.fullScreen = fullScreen
},
// 设置喜欢列表
setFavoriteList(state, list) {
state.favoriteList = list
},
// 设置历史播放记录
setPlayHistory(state, list) {
state.playHistory = list
}
}
export default getters
actions.js(所需要完成的功能)
// 有所需要的功能
const actions = {
// ----------添加一首歌到列表----------
// ----------设置全部歌曲到当前歌曲列表----------
// ----------修改播放模式----------
// ----------删除歌曲----------
// ----------全部清空----------
}
export default actions