移動(dòng)端自定義音頻播放器

1景鼠、自定義的音頻播放器效果圖

music.jpeg

2霞势、代碼

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
    <style>
        .img-box {
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
            padding: 20px 0;
        }
        
        .title {
            text-align: center;
            line-height: 40px;
            font-size: 16px;
            color: #aaa;
        }
        
        .img-rad {
            display: block;
            border: 10px solid #ccc;
            border-radius: 50%;
        }
        
        .progress-box {
            display: flex;
            align-items: center;
            justify-content: space-between;
        }
        
        .progress {
            position: relative;
            width: 250px;
            height: 2px;
            background: #dadada;
        }
        
        .played {
            position: absolute;
            width: 0;
            height: 2px;
            z-index: 10;
            background: #ED2C28;
            left: 0;
            top: 0;
        }
        
        .time {
            position: absolute;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #fff;
            font-size: 10px;
            width: 80px;
            height: 20px;
            border-radius: 10px;
            z-index: 15;
            background: #434343;
            transform: translate(-40px -20px);
            left: 0;
            top: -9px;
        }
        
        .audio-box {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 10px 15px 0;
        }
        
        .icon-btn {
            display: flex;
            align-items: center;
            justify-content: center;
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="img-box">
            <div class="title">周深-起風(fēng)了</div>
            <img class="img-rad" src="http://p1.music.126.net/LpFu9pWQ3tzldjhkLwh4Vw==/109951165291444752.jpg" width="200" height="200" alt="">
        </div>
        <div class="progress-box">
            <div @click="changeFifteen('left')">
                <img width="28" src="https://img-blog.csdnimg.cn/5258cffd0e3d4204855fb58bff908515.png" alt="">
            </div>
            <div ref="progress" class="progress">
                <div :style="'width:' + sliderLeft + 'px'" class="played"></div>
                <div class="time flex flex-item-center flex-just-center" ref="slider" id="slider" @touchstart="sliderTouchStart" @touchmove="sliderTouchMove($event)" @touchend="sliderTouchEnd" class="time absolute-container flex flex-item-center flex-just-center txt-white font10"
                    :style="'left:' + sliderLeft + 'px'">
                    <span>{{currentTime | timeFormat}}</span>/<span>{{duration | timeFormat}}</span>
                </div>
            </div>
            <div @click="changeFifteen('right')">
                <img width="28" src="https://img-blog.csdnimg.cn/7e24d2aabeb247ebbc8da8ff4369ae45.png" alt="">
            </div>
        </div>
        <div class="audio-box">
            <audio src="http://m10.music.126.net/20210904000543/c67d632954d70c2934c5c1ea1b816587/ymusic/obj/w5zDlMODwrDDiGjCn8Ky/3848922654/0b19/a863/3219/0a101cfe8374409a9219f806b445b14e.mp3" ref="audio" preload></audio>
            <div>
                <img width="23" src="https://img-blog.csdnimg.cn/54998c378177452f8bf9a5d66878087c.png" alt="">
            </div>
            <div @click="play" v-if="is_play" class="icon-btn">
                <img width="65" src="https://img-blog.csdnimg.cn/6f282253d8a14cbeb19fa2031a30cf32.png" alt="">
            </div>
            <div @click="play" v-else class="icon-btn">
                <img width="65" src="https://img-blog.csdnimg.cn/dd1bdfffd6644b43a02569562ff2e88a.png" alt="">
            </div>
            <div>
                <img width="23" src="https://img-blog.csdnimg.cn/972679878fa843d5bf4fbd34da6b8153.png" alt="">
            </div>
        </div>
    </div>
</body>
<script>
    var start
    var left
    new Vue({
        el: '#app',
        data() {
            return {
                is_play: false, // 是否播放
                duration: 0, // 總時(shí)長(zhǎng)(秒)
                currentTime: 0, // 已播放時(shí)長(zhǎng)(秒)
                sliderLeft: 0, // 滑塊已滑動(dòng)距離(已播放顏色條寬度)
                slidePercent: 0, // 滑塊已滑動(dòng)百分比
                canSlideWidth: 0, // 滑塊可滑動(dòng)的距離
                progressWidth: 0, // 進(jìn)度條的寬度
                isSlide: false // 是否正在拖動(dòng)
            }
        },
        mounted: function() {
            // 滑塊的寬度
            var sliderWidth = this.$refs.slider.offsetWidth
                // 進(jìn)度條的寬度
            this.progressWidth = this.$refs.progress.offsetWidth
                // 滑塊可滑動(dòng)的寬度
            this.canSlideWidth = this.progressWidth - sliderWidth
                // 等待之后進(jìn)行賦值油额,避免頁(yè)面渲染還沒有數(shù)據(jù)的情況
            setTimeout(() => {
                // 獲取到音頻元素
                var audio = this.$refs.audio;
                // 設(shè)置音頻的總時(shí)長(zhǎng)
                this.duration = audio.duration;
                // 監(jiān)聽音頻實(shí)時(shí)數(shù)據(jù)
                audio.ontimeupdate = e => {
                    // 當(dāng)前播放的時(shí)間(正常播放的進(jìn)度)
                    this.currentTime = Math.floor(audio.currentTime);
                    // 未拖動(dòng)滑塊時(shí)催植,滑塊移動(dòng)的距離
                    if (!this.isSlide) {
                        // 滑塊移動(dòng)距離 = (已播放時(shí)長(zhǎng) / 總時(shí)長(zhǎng)) * 總滑動(dòng)距離
                        this.sliderLeft = audio.currentTime / audio.duration * this.canSlideWidth;
                    }
                }
            }, 200)
        },
        filters: {
            // 將秒數(shù)進(jìn)行格式化
            timeFormat(value) {
                var m = parseInt(value / 60)
                var s = parseInt(value % 60)
                m = m > 10 ? m : '0' + m
                s = s > 10 ? s : '0' + s
                return m + ':' + s
            }
        },
        methods: {
            // 控制播放/暫停
            play() {
                this.is_play = !this.is_play
                var audio = this.$refs.audio
                if (audio.paused) {
                    audio.play()
                } else {
                    audio.pause()
                }
            },
            //進(jìn)度條開始拖動(dòng)
            sliderTouchStart(e) {
                e.preventDefault();
                // 修改拖動(dòng)狀態(tài)為正在拖動(dòng)
                this.isSlide = true;
                // 頁(yè)面寬度
                var pageWidth = document.body.clientWidth;
                // 觸摸時(shí)滑塊相對(duì)頁(yè)面的位置
                start = e.touches[0].pageX;
                // 觸摸點(diǎn)距滑塊左邊緣的距離 = 觸摸時(shí)滑塊相對(duì)頁(yè)面的位置 - (頁(yè)面寬度 - 進(jìn)度條的寬度) / 2 - 滑塊相對(duì)進(jìn)度條左端的距離
                left = start - (pageWidth - this.progressWidth) / 2 - this.$refs.slider.offsetLeft
            },
            sliderTouchMove(e) {
                // 頁(yè)面寬度
                var pageWidth = document.body.clientWidth;
                // 觸摸點(diǎn)距頁(yè)面左邊緣的距離
                var pageX = e.touches[0].pageX
                    // 滑動(dòng)距離占進(jìn)度條的百分比 = (觸摸點(diǎn)距頁(yè)面左端距離 - (頁(yè)面寬度 - 進(jìn)度條寬度) / 2 - 觸摸點(diǎn)距滑塊左邊的相對(duì)位置) / 可滑動(dòng)的總距離
                var sliderLeft = (pageX - (pageWidth - this.progressWidth) / 2 - left) / this.canSlideWidth;
                // 控制左右滑動(dòng)不超出進(jìn)度條范圍(0 < 百分比 < 1)
                if (sliderLeft > 1) sliderLeft = 1;
                if (sliderLeft < 0) sliderLeft = 0;
                // 滑塊的定位left值肮蛹,確定滑塊位置
                this.slidePercent = sliderLeft;
                // 已滑動(dòng)的距離(已播放顏色條寬度)
                this.sliderLeft = sliderLeft * this.canSlideWidth;
            },
            //進(jìn)度條托動(dòng)放開
            sliderTouchEnd() {
                // 修改拖動(dòng)狀態(tài)為
                this.isSlide = false;
                var audio = this.$refs.audio;
                audio.currentTime = audio.duration * this.slidePercent
            },
            // 快進(jìn)快退15秒
            changeFifteen(direction) {
                var audio = this.$refs.audio
                if (direction == 'left') {
                    audio.currentTime -= 15
                } else {
                    audio.currentTime += 15
                }
                this.sliderLeft = audio.currentTime / audio.duration * this.canSlideWidth
            }
        }
    });
</script>

</html>

3勺择、使用說(shuō)明

(1)這個(gè)效果是h5引入vue寫成的
(2)封裝成組件的話需要自己修改一些東西
(3)音樂(lè)鏈接可能已失效,請(qǐng)自行輸入音樂(lè)鏈接

4伦忠、用到的圖片

left15.png
right15.png
played.png
paused.png
last.png
next.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末省核,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子昆码,更是在濱河造成了極大的恐慌气忠,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赋咽,死亡現(xiàn)場(chǎng)離奇詭異旧噪,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)脓匿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門淘钟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人陪毡,你說(shuō)我怎么就攤上這事米母。” “怎么了缤骨?”我有些...
    開封第一講書人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵爱咬,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我绊起,道長(zhǎng)精拟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任虱歪,我火速辦了婚禮蜂绎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘笋鄙。我一直安慰自己师枣,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開白布萧落。 她就那樣靜靜地躺著践美,像睡著了一般。 火紅的嫁衣襯著肌膚如雪找岖。 梳的紋絲不亂的頭發(fā)上陨倡,一...
    開封第一講書人閱讀 52,457評(píng)論 1 311
  • 那天,我揣著相機(jī)與錄音许布,去河邊找鬼兴革。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的杂曲。 我是一名探鬼主播庶艾,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼擎勘!你這毒婦竟也來(lái)了咱揍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤货抄,失蹤者是張志新(化名)和其女友劉穎述召,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蟹地,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡积暖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了怪与。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夺刑。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖分别,靈堂內(nèi)的尸體忽然破棺而出遍愿,到底是詐尸還是另有隱情,我是刑警寧澤耘斩,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布沼填,位于F島的核電站,受9級(jí)特大地震影響括授,放射性物質(zhì)發(fā)生泄漏坞笙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一荚虚、第九天 我趴在偏房一處隱蔽的房頂上張望薛夜。 院中可真熱鬧,春花似錦版述、人聲如沸梯澜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)晚伙。三九已至,卻和暖如春俭茧,著一層夾襖步出監(jiān)牢的瞬間咆疗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工恢恼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人胰默。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓场斑,卻偏偏與公主長(zhǎng)得像漓踢,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子漏隐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

推薦閱讀更多精彩內(nèi)容