这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
一、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>