Vue3项目自学训练------音乐播放器(开源项目)(六)

目录

1、解决用滚动组件的问题

2、bug解决及优化

(1)当前页面刷新会报错:没有路由参数就拿不到数据​编辑

(2)页面一进来数据还没加载完播放按钮没数据播放(MusicList.vue)

(3)加载数据的加载动画(SingerDetail.vue)

(4)返回按钮

(5)点击切换优化滑动过渡效果

3、vueX


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)当前页面刷新会报错:没有路由参数就拿不到数据

 在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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.MUXIAO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值