• Vue开发历程---音乐播放器的继续



    前言

    前面一篇文章Vue开发历程—音乐播放器,实现了播放音乐,以及基本的布局。但是进度条没有实现同步,本文即介绍进度条的实现。

    一、效果图

    进度条

    二、心路历程

    1、elementUI 滑块的使用

     <div class="block" style="margin-top:5px">
    	<el-slider v-model="value" @change="updateSlideTime()" :format-tooltip="formatTooltip">el-slider>
     div>
    
    • 1
    • 2
    • 3

    2、JS的编写

    进度条的状态是实时的,也就是每一秒每一刻都要变化,如何实现这一功能?
    首先需要写一个方法,每30ms更新一次状态,同时在组件挂载完成的时候调用这个方法,从而实现了每30ms,即更新进度条的数值。
    通过refs可以获得audio这个标签,这个标签上有duration(时长),currentTime(当前时间)这两个属性,通过这两个属性,可以计算出来进度的占比。

     updateSongsTime: function () {
                const timer = setInterval(() => {
                    const music = document.getElementById("m_mp3")||null;
                    if (music != null) {
                        this.currentTime = music.currentTime;
                        this.duration = music.duration;
                        this.persent = (this.currentTime / this.duration) * 100;
                    }
    
                }, 30);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    mounted() {
            this.songNum = this.songNames.length;
            const music = this.$refs.player;
            this.updateSongsTime();
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    同时也需要在MusicPlayer.vue组件里面如法炮制,获取父组件的值从而实时更新滑块的状态,因为滑块是写在MusicPlayer组件里面了,但是歌曲的播放在父组件Player.vue里,所以也是用到了组件的通信。

    3、时间的转化

    由于currentTime返回来的是总秒数,而音乐播放器一般都是分:秒这样的格式,所以通过一些简单的数学计算(除以60求分,对60取余求秒)来进行对时长的格式化处理。采用了三目运算符,还对不足10的时间进行了处理,即小于10的数值前面自动补0

    formatTooltip()
            {
                return Math.trunc(this.$parent.currentTime/60)+":"+((Math.trunc(this.$parent.currentTime%60)<10)?("0"+Math.trunc(this.$parent.currentTime%60)):Math.trunc(this.$parent.currentTime%60));
            }
    
    • 1
    • 2
    • 3
    • 4

    #源代码

    代码如下:
    Player.vue

    <template>
        <div class="player_div1">
            <transition name="open" mode="out-in">
                <component v-bind:is="view" @hello="changeSlideState" @play="changePlayState" @lastSongs="lastSongs"
                    @nextSongs="nextSongs" @changeSongsTime="changeSongsTime">component>
            transition>
            <audio class="m_mp3" id="m_mp3" :src="this.songNames[this.index].Url" autoplay loop ref="player" controls
                style="display:none">
    
            audio>
        div>
    
    template>
    
    <script>
    import HidePlayer from '@/part/HidePlayer'
    import MusicPlayer from '@/part/MusicPlayer'
    export default {
        name: 'Player',
        data() {
            return {
                view: MusicPlayer,
                isClose: false,
                isShow: true,
                isRun: 'come',
                index: 0,
                songNum: 2,
                currentTime: 0,
                duration: 0,
                persent: 0,
                songNames: [
                    {
                        id: 6,
                        name: '庐州月-许嵩',
                        Url: require('@/assets/庐州月.mp3'),
                        png: require('@/assets/庐州月.png'),
                    },
                    {
                        id: 7,
                        name: '燕归巢-许嵩',
                        Url: require('@/assets/燕归巢.mp3'),
                        png: require('@/assets/燕归巢.jpg'),
                    },
                    {
                        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;
                }
    
            },
            changeSongsTime(value) {
                const music = document.getElementById("m_mp3");
                music.currentTime = value / 100 * music.duration;
    
            }
            ,
            updateSongsTime: function () {
                const timer = setInterval(() => {
                    const music = document.getElementById("m_mp3")||null;
                    if (music != null) {
                        this.currentTime = music.currentTime;
                        this.duration = music.duration;
                        this.persent = (this.currentTime / this.duration) * 100;
                    }
    
                }, 30)
            }
        }, mounted() {
            this.songNum = this.songNames.length;
            const music = this.$refs.player;
            this.updateSongsTime();
    
        }
    
    }
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177

    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="value" @change="updateSlideTime()" :format-tooltip="formatTooltip">el-slider>
                div>
                
            div>
            
            <div class="m_time">
                    <span>{{nowtime}} / span>
                    <span>{{allTime}}span>
            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: '',
                value:0.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
            },
            changeSlideTime()
            {
                 const timer = setInterval(()=>{
                   this.value = this.$parent.persent;
                   
                },30)
            },
            updateSlideTime()
            {
                this.$emit("changeSongsTime",this.value);
            },
            formatTooltip()
            {
                return Math.trunc(this.$parent.currentTime/60)+":"+((Math.trunc(this.$parent.currentTime%60)<10)?("0"+Math.trunc(this.$parent.currentTime%60)):Math.trunc(this.$parent.currentTime%60));
            }
        },
        watch:
        {
           
    
        },
        computed:{
            nowtime()
            {
                return ((Math.trunc(this.$parent.currentTime/60)<10)?("0"+Math.trunc(this.$parent.currentTime/60)):(Math.trunc(this.$parent.currentTime/60)))+":"+((Math.trunc(this.$parent.currentTime%60)<10)?("0"+Math.trunc(this.$parent.currentTime%60)):(Math.trunc(this.$parent.currentTime%60)));
                        },
            allTime()
            {
                return ((Math.trunc(this.$parent.duration/60)<10)?("0"+Math.trunc(this.$parent.duration/60)):(Math.trunc(this.$parent.duration/60)))+":"+((Math.trunc(this.$parent.duration%60)<10)?("0"+Math.trunc(this.$parent.duration%60)):(Math.trunc(this.$parent.duration%60)));
            }
        } 
        ,mounted() {
            this.songName = this.$parent.songNames[this.$parent.index].name;
            this.changeSlideTime();
    
        }
    
    }
    script>
    
    <style scoped>
    /* 关于播放器的样式 */
    .music {
        width: 100%;
        height: 120px;
        background: black;
        /* 相对浏览器定位 */
        position: fixed;
        left: 0px;
        bottom: 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: 48%;
    }
    
    /* 修改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);
    
    }
    .m_time
    {
        width: 100px;
        height: 20px;
        margin-top: 64px;
        float:left;
        margin-left: 10px;
        font:bold
    }
    
    /* 设置最右边的关闭样式 */
    .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>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277

    HidePlayer.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: 0px;
        /* bottom: 100px; */
        position: fixed;
        background-position-x: -45px;
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    总结

    真可谓是基础不牢,地动山摇,由于CSS,JS学的很浅,现在很多的布局搞不明白,布局效果只有一点点的尝试,导致自己的开发进度变得特别特别缓慢,再次提醒各位C友,一定一定要注重基础的深入学习。勉之哉!!

  • 相关阅读:
    请描述一下Spring MVC的工作流程。在Spring MVC中,DispatcherServlet的作用是什么?
    代码随想录算法训练营第三十八天【动态规划part01】 | 动态规划理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯
    12.NLP中的RNN、LSTM、GRU
    QC1.0、QC2.0、QC3.0、QC4.0协议介绍
    matplotlib基操(三)
    手把手教你语音识别
    2022.11.7-11.13 AI行业周刊(第123期):技术人员的职业发展在哪里?
    Kotlin基础学习 17
    PyQt项目实战1
    电极的制作方法详解
  • 原文地址:https://blog.csdn.net/m0_59792745/article/details/126090567