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

目录

优化一:加载动画

指令注册(加载动画多场景复用)(vue的自定义指令注册app.directive)

优化二:图片懒加载

安装@vueuse/core工具(一个函数合集)

歌手页面


优化一:加载动画

在components下的base文件夹中创建Loading.vue(大致布局)

<template>
    <div class="loading">
        <div class="loading-content">
            <img src="@/assets/images/loading.gif" width="24" height="24" alt="">
            <p class="desc">loading...</p>
        </div>
    </div>
</template>

<script setup>

</script>

<style lang="scss" scoped>
.loading {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate3d(-50%, -50%, 0);
    .loading-content {
        text-align: center;
        .desc {
            line-height: 20px;
            font-size: $font-size-small;
            color: $color-text-l;
        }
    }
}
</style>

在main.js中全局注册的指令

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 全局挂载才能用
import directivePlugin from './plugins'
import './assets/scss/index.scss'

createApp(App).use(store).use(router).use(directivePlugin).mount('#app')

指令注册(加载动画多场景复用)(vue的自定义指令注册app.directive)

在components下创建指令文件夹plugins创建index.js

import loading from '@/components/base/Loading'
import { createApp } from 'vue'

export default {
    install(app) {
        // 加载动画
        app.directive('loading', {
            // 绑定指令DOM
            mounted(el, binding) {
                // console.log(el, binding);
                // loading组件应用对象
                const app = createApp(loading)
                // loading组件的实例对象
                const instance = app.mount(document.createElement('div'))
                el.instance = instance
                if (binding.value) {
                    appendEl(el)
                }
            },
            // 更新时调用
            updated(el, binding) {
                if (binding.value !== binding.oldValue) {
                    binding.value ? appendEl(el) : removeEl(el)
                }
            }
        })
    }

}

function appendEl(el) {
    const style = getComputedStyle(el)
    let arr = ['absolute', 'fixed', 'relative']
    if (arr.indexOf(style.position) === -1) {
        // 绑定的DOM没有定位样式(就加上定位)
        el.classList.add('g-relative')
    }
    el.appendChild(el.instance.$el)
}


function removeEl(el) {
    el.classList.remove('g-relative')
    el.removeChild(el.instance.$el)
}

在Recommend.vue中使用

<template>
  <div class="recommend" v-loading="loading">
    <my-scroll class="recommend-content">
      <div>
        <!-- 轮播 -->
        <div class="slider-wrapper">
          <div class="slider-content">
            <my-slider v-if="sliders.length" :sliders="sliders"></my-slider>
          </div>
        </div>
        <!-- 热门歌单推荐 -->
        <div class="recommend-list">
          <h2 class="list-title">热门歌单推荐</h2>
          <ul>
            <li
              class="recommend-item"
              v-for="(item, index) in albums"
              :key="item.id"
            >
              <div class="icon">
                <img
                  v-img-lazy="item.coverImgUrl"
                  width="60"
                  height="60"
                  alt=""
                />
              </div>
              <div class="text">
                <p class="name">{{ item.name }}</p>
                <p class="description">{{ item.description }}</p>
              </div>
            </li>
          </ul>
        </div>
      </div>
    </my-scroll>
  </div>
</template>

<script setup>
import { getRecommend, getRecommendAlbum } from "@/service/recommend";
import { computed, onMounted, ref } from "vue";
import MySlider from "@/components/base/Slider";
import MyScroll from "@/components/base/Scroll";

const sliders = ref([]);
const albums = ref([]);

// 为true出现加载动画,false消失
const loading = computed(() => !sliders.value.length || !albums.value.length);


</script>

<style lang="scss" scoped>
</style>

优化二:图片懒加载

安装@vueuse/core工具(一个函数合集)

npm install @vueuse/core --save

在components下指令文件夹plugins的index.js

import loading from '@/components/base/Loading'
import { createApp } from 'vue'
import { useIntersectionObserver } from '@vueuse/core'
//默认占位图片
import defaultImg from '@/assets/images/lazy.png'

export default {
    install(app) {
        // 图片懒加载
        app.directive('img-lazy', {
            mounted(el, binding) {
                // 全部设置为占为图片
                el.src = defaultImg
                const { stop } = useIntersectionObserver(el, ([{ isIntersecting }]) => {
                    //isIntersecting: true进入了视口区域,false未进入
                    if (isIntersecting) {
                        // 加载失败
                        el.onerror = function () {
                            el.src = defaultImg
                        }
                        el.src = binding.value
                        // 停止监听
                        stop()
                    }
                })
            }
        })
    }

}

使用图片懒加载指令

<img v-img-lazy="item.coverImgUrl" width="60" height="60" alt="" />

歌手页面

Singer.vue页面

<template>
  <div class="singer">
      <my-singerList :singerList="singerList"></my-singerList>
  </div>
</template>

<script setup>
import { computed, onMounted, ref } from "vue";
import { getSingerList } from "@/service/singer";
import MySingerList from "@/components/SingerList"

const singerList = ref([]);
//创建26个大写字母的数组
const arrStrUppercase = computed(() => {
  let arr = ["热"];
  for (let i = 65; i < 91; i++) {
    // console.log(i);
    arr.push(String.fromCharCode(i));
  }
  return arr;
});

onMounted(async () => {
  // console.log(arrStrUppercase);
  const result = await getSingerList(arrStrUppercase.value);
  //   console.log(result);
  singerList.value = result;
});
</script>

<style lang="scss" scoped>
</style>

使用String.fromCharCode()转码 (数字转字母)

 在service文件夹下创建singer.js歌手数据的接口

import { get } from './base'

// 拿到26个字母的数组,遍历数组发起请求
export function getSingerList(arrStr) {
    // console.log(arrStr);
    let singerList = []//接收所有的数据
    let promiseArr = []//

    for (let i = 0; i < arrStr.length; i++) {
        promiseArr.push(new Promise((resolve, reject) => {
            handle(arrStr[i], singerList, resolve)
        }))
    }
    // 所有promise请求成功才算成功
    // console.log(promiseArr);
    return Promise.all(promiseArr).then(() => {
        singerList.sort((a,b) => {
            return a.tag.charCodeAt() - b.tag.reject()
        })
        // console.log(singerList.pop());
        singerList.unshift(singerList.pop())
        return singerList
    })
}
// 请求数据接口
function handle(item, singerList, resolve) {
    if (item === '热') {
        get('/top/artists', {
            limit: 30
        }).then((result) => {
            // console.log(result)
            singerList.push({
                tag: item,
                nameArr: result.artists
            })
        }).catch(err => {
            throw err
        })
    } else {
        // 通过首字母查询歌手
        get('/artist/list', {
            initial: item,
            type: -1,
            area: -1
        }).then((result) => {
            // console.log(result)
            singerList.push({
                tag: item,
                nameArr: result.artists
            })
        }).catch(err => {
            throw err
        })
    }
}

在components下新建SingerList.vue

<template>
  <div class="singer-list">
    <ul class="view-scroll">
      <li class="group" v-for="group in singerList" :key="group.tag">
        <h2 class="title">{{ group.tag }}</h2>
        <ul>
          <li class="item" v-for="item in group.nameArr" :key="item.id">
            <div class="avatar">
              <img v-img-lazy="item.picUrl" alt="" />
            </div>
            <span class="name">{{ item.name }}</span>
          </li>
        </ul>
      </li>
    </ul>
  </div>
</template>

<script setup>
// 接收数据
const props = defineProps(["singerList"]);
</script>

<style lang="scss" scoped>

</style>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
如果你想进行VUE项目实战并开发一个VUE后台管理系统,以下是一些建议和资源可供参考。 首先,如果你是大学即将毕业或自学前端且缺乏项目经验,你可以考虑以下几点: - 寻找相关的在线教程或课程,这些资源通常会提供详细的步骤和案例来帮助你实践VUE项目。你可以搜索一些知名的在线教育平台,如网易云课堂、慕课网等。 - 参考md文档,一些教程可能会总结在md文档中,这将帮助你更好地理解项目开发过程中的每一步。 - 观看相关的视频教程,比如在哔哔哩哩上搜索"程序员Allen",他提供了一些关于VUE项目实战的视频教程。 另外,如果你想开发一个基于VUE的后台管理系统,你需要考虑以下几点: - 确定使用的技术栈。目前最新的技术栈中,Vue3.2、TypeScript、Vite3、Pinia、Element-Plus是一些常见的选择。这些技术将帮助你更高效地开发后台管理系统。 - 寻找开源的后台管理框架。你可以搜索一些开源的后台管理框架,这些框架提供了一些常用的组件、Hooks、指令、动态路由、按钮级别权限控制等功能。这将节省你的开发时间和提高效率。 总之,为了进行VUE项目实战和开发后台管理系统,你可以参考在线教程、学习md文档、观看相关视频教程,同时寻找开源的后台管理框架来加速你的开发过程。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Vue项目实战 —— 后台管理系统( pc端 ) —— Pro最终版本](https://blog.csdn.net/m0_57904695/article/details/129730440)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [Vue项目实战 —— 后台管理系统( pc端 )](https://blog.csdn.net/m0_67391377/article/details/124818830)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Mr.MUXIAO

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

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

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

打赏作者

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

抵扣说明:

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

余额充值