首先,编写动画。

.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="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/this.$parent.songNames[this.$parent.index].png" width="90px" :class="this.$parent.isRun">
</div>

本文转载于:

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

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

 

本文来源:

博客园:https://www.cnblogs.com/smileZAZ/archive/2023/01/12/17047009.html

为什么会产生组件内的通信?原因在于: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="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/this.$parent.songNames[this.$parent.index].png" width="90px" :class="this.$parent.isRun">
</div>

本文转载于:

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

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

 

本文来源:

博客园:https://www.cnblogs.com/smileZAZ/archive/2023/01/12/17047009.html

 参考了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="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/this.$parent.songNames[this.$parent.index].png" width="90px" :class="this.$parent.isRun">
</div>

本文转载于:

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

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

 

本文来源:

博客园:https://www.cnblogs.com/smileZAZ/archive/2023/01/12/17047009.html

三、代码

代码如下: MusicPlayer.vue

<template>
<div class="music">
<!-- 占位 -->
<div class="m_hold">
</div>
<div class="m_img">
<img :src="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/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">
<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="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/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="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/this.$parent.songNames[this.$parent.index].png" width="90px" :class="this.$parent.isRun">
</div>

本文转载于:

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

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

 

本文来源:

博客园:https://www.cnblogs.com/smileZAZ/archive/2023/01/12/17047009.html

二、效果

效果如下:

三、代码

代码如下: MusicPlayer.vue

<template>
<div class="music">
<!-- 占位 -->
<div class="m_hold">
</div>
<div class="m_img">
<img :src="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/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">
<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="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/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="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/this.$parent.songNames[this.$parent.index].png" width="90px" :class="this.$parent.isRun">
</div>

本文转载于:

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

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

 

本文来源:

博客园:https://www.cnblogs.com/smileZAZ/archive/2023/01/12/17047009.html

 2、对象方法

二、效果

效果如下:

三、代码

代码如下: MusicPlayer.vue

<template>
<div class="music">
<!-- 占位 -->
<div class="m_hold">
</div>
<div class="m_img">
<img :src="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/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">
<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="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/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="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/this.$parent.songNames[this.$parent.index].png" width="90px" :class="this.$parent.isRun">
</div>

本文转载于:

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

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

 

本文来源:

博客园:https://www.cnblogs.com/smileZAZ/archive/2023/01/12/17047009.html

一、audio标签的使用

1、Audio 对象属性

 2、对象方法

二、效果

效果如下:

三、代码

代码如下: MusicPlayer.vue

<template>
<div class="music">
<!-- 占位 -->
<div class="m_hold">
</div>
<div class="m_img">
<img :src="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/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">
<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="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/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="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/this.$parent.songNames[this.$parent.index].png" width="90px" :class="this.$parent.isRun">
</div>

本文转载于:

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

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

 

本文来源:

博客园:https://www.cnblogs.com/smileZAZ/archive/2023/01/12/17047009.html

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

一、audio标签的使用

1、Audio 对象属性

 2、对象方法

二、效果

效果如下:

三、代码

代码如下: MusicPlayer.vue

<template>
<div class="music">
<!-- 占位 -->
<div class="m_hold">
</div>
<div class="m_img">
<img :src="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/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">
<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="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/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="https://www.cnblogs.com/smileZAZ/archive/2023/01/12/this.$parent.songNames[this.$parent.index].png" width="90px" :class="this.$parent.isRun">
</div>

本文转载于:

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

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

 

本文来源:

博客园:https://www.cnblogs.com/smileZAZ/archive/2023/01/12/17047009.html

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注