记录--Vue开发历程---音乐播放器

news2024/11/18 5:29:16

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

一、audio标签的使用

1、Audio 对象属性

 2、对象方法

二、效果

效果如下:

三、代码

代码如下: MusicPlayer.vue

<template>
    <div class="music">
        <!-- 占位 -->
        <div class="m_hold">

        </div>
        <div class="m_img">
            <img :src="this.$parent.songNames[this.$parent.index].png" width="90px" :class="this.$parent.isRun">
        </div>
        <!-- 歌曲信息 -->
        <div class="m_text">
            {{ this.$parent.songNames[this.$parent.index].name }}
            <div class="block" style="margin-top:5px">
                <el-slider :v-model="value1"></el-slider>
            </div>
        </div>
        <!-- 按钮 -->
        <div class="m_btn">
            <a href="#" class="m_prev" @click="playLastSong()"></a>
            <a href="#" class="m_play" @click="changeState()" v-show="this.$parent.isShow"></a>
            <a href="#" class="m_pause" @click="changeState()" v-show="!this.$parent.isShow"></a>
            <a href="#" class="m_next" @click="playNextSong()"></a>
        </div>
        <!-- 折叠功能 -->
        <div class="m_close" @click="changeCloseState()">
            <a href=""></a>
        </div>

    </div>
</template>

<script>
export default {
    name: 'MusicPlayer',
    data() {
        return {
            songName: '',
            value1:0

        }
    },
    methods: {
        changeState() {

            this.$emit("play")
        },
        changeCloseState() {
            this.$emit("hello");
        },
        playNextSong() {
            this.$emit("nextSongs");
            this.songName = this.$parent.songNames[this.$parent.index].name
        },
        playLastSong() {
            this.$emit("lastSongs");
            this.songName = this.$parent.songNames[this.$parent.index].name
        }
    },
    watch:
    {
       

    }, mounted() {
        this.songName = this.$parent.songNames[this.$parent.index].name
    }

}
</script>

<style scoped>
/* 关于播放器的样式 */
.music {
    width: 100%;
    height: 120px;
    background: black;
    /* 相对浏览器定位 */
    position: absolute;
    left: 0px;
    bottom: 100px;
    border-bottom: 50px;
    /* 透明度 */
    opacity: 0.8;
    /* 阴影值 */
    box-shadow: 10px 15px 15px 1px black
}

.music .m_hold {
    float: left;
    width: 90px;
    height: 90px;
}

/* 调整音乐盒图片 */
.music .m_img {
    margin-top: 15px;
    margin-left: 10px;
    margin-right: 10px;
    /* 左浮动 */
    float: left;
    width: 90px;
    height: 90px;
    border-radius: 50%;
    overflow: hidden;

}

/* 修改文字 */
.music .m_text {
    /* 左浮动 */
    float: left;
    color: white;
    font-size: 20px;
    /* 字体加粗 */
    font-weight: bold;
    margin-top: 25px;
    margin-left: 20px;
    margin-bottom: 10px;
    width: 25%;

}

/* 使得所有a标签一起移动 */
.music .m_btn {
    float: left;
    position: absolute;
    /* 绝对定位:防止歌曲名称过长,挤出div */
    left: 40%;
}

/* 修改a标签 */
.music .m_btn a {
    width: 32px;
    height: 32px;
    float: left;
    margin-top: 50px;
    margin-left: 20px;
    background: url(@/assets/player_bg.png);

}

.music .m_btn .m_prev {
    background-position: -69px 0px;
}

.music .m_btn .m_next {
    background-position: -150px 0px;
}

.music .m_btn .m_play {
    background-position: -107px -5px;
}

.music .m_btn .m_prev:hover {
    background-position: -69px -32px;
}

.music .m_btn .m_next:hover {
    background-position: -150px -32px;
}

.music .m_btn .m_play:hover {
    background-position: -107px -47px;
}

.music .m_btn .m_pause {
    background-position: -292px -94px;
}

.music .m_btn .m_pause:hover {
    background-position: -334px -94px;
}

/* 还有一个悬停 没写 */
/* 设置最右边的关闭样式 */
.music .m_close {
    float: right;
    background: white;
    cursor: pointer;
    width: 23px;
    height: 100px;
    margin-top: 10px;
    background: url(@/assets/player_bg.png);

}

/* 设置最右边的关闭样式 */
.music_hide {
    float: left;
    background: white;
    cursor: pointer;
    width: 23px;
    height: 100px;
    margin-top: 2px;
}

.go {
    animation: bounce-in 2s linear infinite;
}

.come {
    animation: none;
}

@keyframes bounce-in {
    from {
        transform: rotate(0deg);
    }

    to {
        transform: rotate(360deg);
    }
}

.open-enter-active {
    animation: slide-in linear 0.5s;
}

.open-leave-active {
    animation: slide-in reverse linear 0.5s;
}

@keyframes slide-in {
    from {
        transform: translateX(-100%);
    }

    to {
        transform: translateX(0%);
    }
}
</style>

HideMusic.vue

<template>
    <div class="music_hide" @click="changeCloseState()"><a href="#" class="m_open"></a></div>
</template>

<script>
export default {
    name:'HidePlayer',
    methods:{
        changeCloseState()
        {
            this.$emit("hello");
        }
    }
}
</script>

<style scoped>
.music_hide {
    float: left;
    background: url(@/assets/player_bg.png);
    cursor: pointer;
    width: 23px;
    height: 100px;
    margin-top: 10px;
    bottom: 100px;
    position: absolute;
    background-position-x: -45px;
}
</style>

MyPlayer.vue

<template>
    <div>
        <transition name="open" mode="out-in">
            <component v-bind:is="view" @hello="changeSlideState" @play="changePlayState" @lastSongs="lastSongs"
                @nextSongs="nextSongs"></component>
        </transition>
        <audio class="m_mp3" id="m_mp3" :src="this.songNames[this.index].Url" autoplay loop>

        </audio>
    </div>

</template>

<script>
import HidePlayer from '@/part/HidePlayer'
import MusicPlayer from '@/part/MusicPlayer'
export default {
    name: 'MyPlayer',
    data() {
        return {
            view: MusicPlayer,
            isClose: false,
            isShow: true,
            isRun: 'come',
            index: 0,
            songNum: 2,
            currentTime: '0:00',
            duration: '0:00',
            songNames: [
                {
                    id: 1,
                    name: '张韶涵-篇章',
                    Url: require('@/assets/张韶涵-篇章.mp3'),
                    png: require('@/assets/篇章.png'),
                },
                {
                    id: 2,
                    name: '爱就一个字 抒情版',
                    Url: require('@/assets/爱就一个字 抒情版.mp3'),
                    png: require('@/assets/爱就一个字.png'),
                },
                {
                    id: 3,
                    name: '最伟大的作品-周杰伦',
                    Url: require('@/assets/最伟大的作品-周杰伦.mp3'),
                    png: require('@/assets/周杰伦.jpg'),
                },
                {
                    id: 4,
                    name: '等你下课 (with 杨瑞代)-周杰伦',
                    Url: require('@/assets/等你下课 (with 杨瑞代)-周杰伦.mp3'),
                    png: require('@/assets/等你下课.png'),
                },
                {
                    id: 5,
                    name: '告白气球-周杰伦',
                    Url: require('@/assets/告白气球-周杰伦.mp3'),
                    png: require('@/assets/告白气球.png'),
                },
                {
                    id: 6,
                    name: '还在流浪-周杰伦',
                    Url: require('@/assets/还在流浪-周杰伦.mp3'),
                    png: require('@/assets/还在流浪.png'),
                },
            ]
        }
    },
    components: {
        HidePlayer,
        MusicPlayer
    },
    methods: {
        changeSlideState() {
            this.isClose = !this.isClose;
            if (this.isClose) {
                this.view = HidePlayer;
            } else {
                this.view = MusicPlayer;
            }
        },
        changePlayState() {
            if (!this.isShow) {
                this.isShow = true;
                this.isRun = "come";
                document.getElementById("m_mp3").pause();
            } else {
                this.isShow = false;
                this.isRun = "go";
                var my_mp3 = document.getElementById("m_mp3");
                my_mp3.play();


            }
        },
        nextSongs() {
            if (this.isShow) {
                this.isShow = false;
                this.isRun = "go";
            }
            this.index = (this.index + 1) % this.songNum;
        },
        lastSongs() {
            if (this.isShow) {
                this.isShow = false;
                this.isRun = "go";
            }
            if (this.index == 0) {
                this.index = this.songNum - 1;
            } else {
                this.index = this.index - 1;
            }

        }
    }, mounted() {
        this.songNum = this.songNames.length;
        
    }

}
</script>

<style scoped>
.open-enter-active {
    animation: slide-in linear 0.5s;
}

.open-leave-active {
    animation: slide-in reverse linear 0.5s;
}

@keyframes slide-in {
    from {
        transform: translateX(-100%);
    }

    to {
        transform: translateX(0%);
    }
}
</style>

四、难点解析

1、过渡动画的实现

 参考了vue文档过渡&动画中多个组件的过渡(下面三份代码)

<transition name="component-fade" mode="out-in">
  <component v-bind:is="view"></component>
</transition>
new Vue({
  el: '#transition-components-demo',
  data: {
    view: 'v-a'
  },
  components: {
    'v-a': {
      template: '<div>Component A</div>'
    },
    'v-b': {
      template: '<div>Component B</div>'
    }
  }
})
.component-fade-enter-active, .component-fade-leave-active {
  transition: opacity .3s ease;
}
.component-fade-enter, .component-fade-leave-to
/* .component-fade-leave-active for below version 2.1.8 */ {
  opacity: 0;
}

因此分化出MusicPlayer.vue 和 HideMusic.vue,由此又产生了组件内通信的问题。

2、组件内通信

为什么会产生组件内的通信?原因在于:MusicPlayer组件和HidePlayer组件,只能有一个展示,但是在不展示的过程中,他的数据应该也是实时改变的。例如MusicPlayer组件上有播放按钮,如果不采用组件通信,那么MusicPlayer重新渲染的时候,播放按钮会回到最初的设定,是不符合逻辑的。所以需要采用组件内通信的方式。实现的方式也比较简单,子组件直接访问父组件的数据,子组件通过$emit调用父组件的方法,修改父组件的数据。

3、旋转动画的实现

 首先,编写动画。

.go {
    animation: bounce-in 2s linear infinite;
}

.come {
    animation: none;
}

@keyframes bounce-in {
    from {
        transform: rotate(0deg);
    }

    to {
        transform: rotate(360deg);
    }
}

然后,动态绑定class,isRun两个值即为"go","come"。

<div class="m_img">
   <img :src="this.$parent.songNames[this.$parent.index].png" width="90px" :class="this.$parent.isRun">
</div>

本文转载于:

https://blog.51cto.com/u_15807146/5807883

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/160147.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【QFD】质量保证需求

QFD体系把前端商业策略成果和产品有效开发紧密连接起来工具。QFD是强调需求与功能的对应&#xff0c;验证确定的市场需求与产品功能设计的关联性&#xff0c;与功能之间&#xff0c;与需求之间的矛盾性&#xff0c;也叫质量屋。 1.什么是QFD 什么是QFD质量功能展开&#xff0…

代码随想录第59天|503.下一个更大元素II ● 42. 接雨水

503.下一个更大元素2 和下一个更大元素基本相同&#xff0c;就多了一个循环数组的问题 处理方法&#xff1a; 循环的次数*2 利用i%nums.size()得到处理的下标&#xff0c;这样当遍历到nums的最后一个元素的时候&#xff0c;向单调栈中插入其下标nums.size()-1,之后将其与下标n…

C语言进阶(7)——联合体和枚举

文章目录1 枚举1.1 含义1.2 定义1.3 枚举的优点1.4 枚举的使用2 联合体&#xff08;共用体&#xff09;2.1 联合类型的定义2.2 联合体的特点2.3联合体大小的计算1 枚举 1.1 含义 枚举就是一一列举。 1.2 定义 枚举是定义常量&#xff0c;默认值 0&#xff0c;然后数自增。 …

go:快速升级Go版本,我几分钟就解决了

底层依赖升级了&#xff0c;那我们也要跟着升&#xff0c;go版本需要升级到1.18以上&#xff0c;网上对比了一些教程&#xff0c;发现这个方法最便捷快速 目录当前Go版本下载高版本Go登录 [Go官网](https://go.dev/dl/)下载对应版本部署升级Go版本备份旧版本部署新版本当前Go版…

从0到1完成一个Node后端(express)项目(一、初始化项目、安装nodemon)

初识express 因为上个专栏的vue项目&#xff0c;后端是用node写的&#xff0c;所以这里教大家怎么去写 Express 简介&#xff1a; Express 是基于 Node.js 平台&#xff0c;快速、开放、极简的 Web 开发框架通俗的理解: Express 的作用和 Node.is内置的 http 模块类似&#xff…

MongoDB副本详解

概念 MongoDB副本集是一组维护相同数据集的mongod服务&#xff0c;可以提供冗余和高可用&#xff0c;是所有生产部署的基础&#xff1b; mysql主从复制和mongodb副本集的区别 主从复制的主从是固定的&#xff0c;副本集是不固定的&#xff0c;可以自动切换 副本集角色 主节点&a…

prototext format 随机空格

prototext format 随机空格问题简述代码复现解密结论总结问题简述 golang 语言&#xff0c;在使用 prototext 进行 format 的时候&#xff0c;相同的代码输出结果不唯一&#xff0c;有的时候字段之间是两个空格&#xff0c;有的时候是一个空格。 代码 先上pb文件 syntax &…

【寒假每日一题】洛谷 P6414 [COCI2014-2015#1] PROSJEK

题目链接&#xff1a;P6414 [COCI2014-2015#1] PROSJEK - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目描述 有一个数列 a&#xff0c;现在按照下列公式求出一个数列 b&#xff1a; 给你数列 b&#xff0c;请求出数列 a。 输入格式 第一行一个整数 n &#xff0c;表示…

bugku-reverse-入门逆向 Easy_vb re 游戏过关 逆向入门

入门逆向下载文件 解压后 拖入IDA中Easy_vb同样方法 解压后 拖入IDAEasy_re下载解压后 打开似乎有点逗查下壳先拖入IDA 选中这两行字符 转译单击a 得到flag游戏过关下载文件 解压打开 发现要把8个都点亮 每次输入会把输入的数本身和他上一个下一个都改变状态&#xff0c;当…

Jenkin权限控制——基于角色授权策略

开启授权策略 Jenkins的项目权限控制通过【授权策略】实现&#xff0c;【授权策略】需要plugins提供&#xff0c;首先需要安装Role-based Authorization Strategy 安装Role-based Authorization Strategy 管理Jenkins——》插件管理——》搜素——》Role-based Authorizatio…

企微机器人使用及内容配置文档

如何使用群机器人 在终端某个群组添加机器人之后&#xff0c;创建者可以在机器人详情页看的该机器人特有的webhookurl。开发者可以按以下说明a向这个地址发起HTTP POST 请求&#xff0c;即可实现给该群组发送消息。下面举个简单的例子. 假设webhook是&#xff1a;https://qyapi…

【Git 从入门到精通】Git中常用的指令(含使用Git维护一个项目的完整操作)

文章目录一、使用git维护一个项目完整操作1.设置用户名与邮箱2.初始化项目中的Git3.使用Git追踪项目中的文件4.提交一次代码5.后期项目的更新与维护附录、常用命令一览表一、使用git维护一个项目完整操作 1.设置用户名与邮箱 注意:这个设置的并不是将代码提交到github或者gite…

CAD动态块操作实例:绘制剖面符号

CAD动态块与普通的CAD图块相比&#xff0c;其图形夹点更多&#xff0c;设计师可以利用动态块的夹点对图形进行快速调整&#xff0c;自由拉伸长度、随心切换隐藏形态等。本节&#xff0c;给大家分享一下浩辰CAD软件中利用CAD动态块的极轴拉伸功能来绘制剖面符号的具体操作步骤。…

[杂记]算法: 并查集

0. 引言 我们考虑如何计算一个图连通分量的个数. 假定简单无向图GGG有两个连通分量(子图)G1,G2G_1, G_2G1​,G2​, 如下图所示: 一个很自然的想法是, 要想求连通分量个数, 我们可以使用Full-DFS算法, 也就是我们从某个点开始深度优先搜索, 并标记访问过的元素. 随后挨个顶点…

高等数学(第七版)同济大学 总习题十一 个人解答

高等数学&#xff08;第七版&#xff09;同济大学 总习题十一 函数作图软件&#xff1a;Mathematica 1.填空&#xff1a;\begin{aligned}&1. \ 填空&#xff1a;&\end{aligned}​1. 填空&#xff1a;​​ (1)第二类曲线积分∫ΓPdxQdyRdz化成第一类曲线积分是_____&am…

Yarn 下载安装及常用配置和命令总结

title: Yarn 下载安装及常用配置和命令总结 date: 2023-01-13 14:47:32 tags: 开发工具及环境 categories:开发工具及环境 cover: https://cover.png feature: false 1. Node.js 建议先安装好 Node.js&#xff0c;见另一篇&#xff1a;Node.js 多版本安装及 NPM 镜像配置_凡 …

Materials - 角色分层材质规范

之前编写的解释性文档&#xff0c;归档发布&#xff1b;在传统贴图中&#xff0c;以BaseColor贴图为例&#xff0c;我们将几乎所有纹理信息都集中到一张贴图上&#xff0c;比如下图中&#xff0c;就有金属、皮革和布料等各种质感的纹理信息&#xff1a;即使是4K的贴图&#xff…

在Win10下装VMware17后,[ 安装VMware Tools ]选项灰色的解决办法

一、说明 菜单【虚拟机】【安装VMware Tools】按钮为灰色&#xff0c;无法实现【安装VMware Tools】的功能&#xff0c;如何解决&#xff0c;使这个功能可以实现&#xff1f;本文介绍此过程。 二、问题发现 在Win10下安装Vmware17后&#xff0c;生成ubuntu18的虚拟机&#xff…

基于java(springboot+mybatis)汽车信息管理系统设计和实现以及文档

基于java(springbootmybatis)汽车信息管理系统设计和实现以及文档 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言…

行业分享:光伏行业如何利用视觉检测系统降本增效?

导语&#xff1a;机器视觉检测已在光伏产品生产的各个环节中&#xff0c;为产品产量与质量提供可靠保障。维视智造作为光伏组件视觉检测系统领先者&#xff0c;为企业提供专业、系统、稳定的光伏组件视觉检测解决方案&#xff0c;可保证0漏检&#xff0c;全面提升生产效率。一、…