小程式自定義音訊元件,帶滾動條,IOS迴圈失效問題

清風白水發表於2018-08-09

摘要:首先自定義音訊元件,是因為產品有這樣的需求,需要如下樣式的

小程式自定義音訊元件,帶滾動條,IOS迴圈失效問題

而微信小程式API給我們提供的就是這樣的

小程式自定義音訊元件,帶滾動條,IOS迴圈失效問題

而且產品需要小程式有後臺播放功能,所以我們不考慮小程式的 audio 元件,即使官方推薦更強大的  wx.createInnerAudioContext 但是不符合需求,所以這裡用到的是 backgroundAudioManager()

https://developers.weixin.qq.com/miniprogram/dev/api/getBackgroundAudioManager.html

分析一下:這個頁面構成,主要就是進度條和一些icon,進度條之前我自定義了一版,但是效果不理想,最後重構了頁面,所以這裡用的就是 slider 滑動選擇器 https://developers.weixin.qq.com/miniprogram/dev/component/slider.html

  • audio.wxml
<view class="audio">
    <image class="bg" src="{{audio_article.lessonImg}}"></image>
    <image mode="aspectFill" class="poster" src="{{audio_article.lessonImg}}"></image>
    <view class="control-process">
        <text class="current-process">{{current_process}}</text>
        <slider class="slider" 
            bindchange="hanle_slider_change" 
            bindtouchstart="handle_slider_move_start" 
            bindtouchend="handle_slider_move_end" 
            min="0" 
            block-size="16" 
            max="{{slider_max}}" 
            activeColor="#fff" 
            backgroundColor="rgba(255,255,255,.3)" 
            value="{{slider_value}}"
        />
        <text class="total-process">{{total_process}}</text>
    </view>
    <view class="icon-list ">
        <image bindtap="prev" mode="widthFix" src="{{is_first_page?'/images/audio_prev_no.png':'/images/audio_prev.png'}}" class="audio-icon"></image>
        <image mode="widthFix" src="{{is_play? '/images/audio_play.png': '/images/audio_paused.png'}}" class="audio-icon audio-play" bindtap="audio_play"></image>
        <image bindtap="next" mode="widthFix" src="{{is_last_page?'/images/audio_next_no.png':'/images/audio_next.png'}}" class="audio-icon"></image>
        <image hidden mode="widthFix" class="pattern" src="{{is_loop ? '/images/audio_loop.png': '/images/audio_un_loop.png'}}" bindtap="play_loop"></image>
    </view>
</view>
複製程式碼
滑動事件 bindchange="hanle_slider_change" 
開始滑動 bindtouchstart="handle_slider_move_start" 
停止滑動 bindtouchend="handle_slider_move_end" 
複製程式碼
  • audio.wxss

.audio {
    position: relative;
    width: 750rpx;
    height: 640rpx;
    padding: 60rpx 32rpx 52rpx;
    box-sizing: border-box;
    text-align: center;
    overflow: hidden;
    background: rgba(0,0,0,.18);
}

.audio .bg {
    position: absolute;
    top: 0;
    left: -100%;
    bottom: 0;
    right: 0;
    margin: auto;
    width: 300%;
    height: 300%;
    z-index: -1;
    filter: blur(40rpx);
    
}
.editor {
    padding: 32rpx;
    box-sizing: border-box;
    color: #333;
    font-size: 28rpx;
    background: #fff;
}
.editor view {
    max-width: 100% !important;
}

.audio .poster {
    width: 238rpx;
    height: 336rpx;
}
/* 音訊滾動條start */
.control-process {
    margin-top: 20rpx;
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.control-process .slider {
    width: 526rpx;
}
.control-process text {
    font-size: 24rpx;
    color: #fff;
}
/* 音訊滾動條end */
.audio .icon-list {
    position: relative;
    margin: 0 auto;
    line-height: 102rpx;
}

.audio .icon-list .audio-icon + .audio-icon {
    margin-left: 72rpx;
}

.audio .icon-list .pattern {
    position: absolute;
    right: 20rpx;
}

.audio image {
    width: 64rpx;
    height: 64rpx;
    vertical-align: middle;
}

.audio .audio-play {
    width: 92rpx;
    height: 92rpx;
}

.audio .pattern {
    position: absolute;
    top: 0;
    bottom: 0;
    margin: auto 0;
    width: 44rpx;
    height: 44rpx;
}

/* 音訊end  */
複製程式碼
  • audio.js
/**
 * @author: 清風白水 https://www.cnblogs.com/luxiaoyao/
 * @date: 2018/07/20 14:36:00
 * @program: 重構音訊頁面
 */
const APP = getApp()
const AUDIOMANAGER = getApp().globalData.global_bac_audio_manager.manage
const AUDIO = getApp().globalData.global_bac_audio_manager
Page({
    onLoad: function (e) {
        let that = this,
            request_param = {
                articleId: e.articleId
            }

        this.setData({
            article_id: e.articleId
        })

        wx.request({
            url: 'your url',
            method: 'POST',
            data: {},
            header: {
                'Content-Type': 'application/json;text/html;charset=utf-8;' 
                },
            success: (res) => {
                if (res.data.code == 'A00000') {
                    AUDIOMANAGER.onPlay(() => {
                        setTimeout(() => {
                            that.setData({
                                is_loading: true
                            })
                        }, 300)
                    })

                    let response = res.data.data.information

                    // 如果不是從懸浮按鈕播放,就重新賦值
                    if (e.articleId == AUDIO.id && AUDIO.is_play) {
                        wx.seekBackgroundAudio({
                            position: Math.floor(AUDIO.time)
                        })
                    } else {
                        audio_background_play(response)
                    }

                    // 置灰上一首下一首
                    if (response.preArticleId == 0) {
                        that.setData({
                            is_first_page: true
                        })
                    }
                    if (response.nextArticleId == 0) {
                        that.setData({
                            is_last_page: true
                        })
                    }
                }
            }
        })

        //背景音訊播放進度更新事件
        AUDIOMANAGER.onTimeUpdate(() => {
            if (!that.data.is_moving_slider) {
                that.setData({
                    current_process: format(AUDIOMANAGER.currentTime),
                    slider_value: Math.floor(AUDIOMANAGER.currentTime),
                    total_process: format(AUDIOMANAGER.duration),
                    slider_max: Math.floor(AUDIOMANAGER.duration)
                })
            }
            AUDIO.time = AUDIOMANAGER.currentTime
        })

        // 背景音訊播放完畢
       AUDIOMANAGER.onEnded(() => {
                    if (!that.data.is_loop) {
                        that.next()
                    } else {
                        // 單曲迴圈
                        that.setData({
                            slider_value: 0,
                            current_process: '00:00',
                        })
                       audio_background_play(response)
                    }
                })
    },
    // 拖動進度條,到指定位置
    hanle_slider_change(e) {
        const position = e.detail.value
        this.seekCurrentAudio(position)
    },
    // 拖動進度條控制元件
    seekCurrentAudio(position) {
        // 更新進度條
        let that = this

        wx.seekBackgroundAudio({
            position: Math.floor(position),
            success: function () {
                AUDIOMANAGER.currentTime = position
                that.setData({
                    current_process: format(position),
                    slider_value: Math.floor(position)
                })
            }
        })
    },
    // 進度條滑動
    handle_slider_move_start() {
        this.setData({
            is_moving_slider: true
        });
    },
    handle_slider_move_end() {
        this.setData({
            is_moving_slider: false
        });
    },
    // 點選播放暫停
    audio_play: function () {
        let that = this

        if (this.data.is_play) {
            that.setData({
                is_play: false
            })
            wx.pauseBackgroundAudio()
        } else if (!this.data.is_play && this.data.is_ended) { // 這裡是判斷如果迴圈播放結束,沒有下一首,重新播放 is_ended  是否是最後一首
            audio_background_play(that.data.audio_article)
            that.setData({
                is_play: true,
                is_ended: false
            })
        } else if(!this.data.is_play){
            that.setData({
                is_play: true
            })
            wx.playBackgroundAudio()
        }
        AUDIO.is_play = !AUDIO.is_play
    },
    // 點選是否迴圈
    play_loop: function () {
        let that = this

        if (this.data.is_loop) {
            that.setData({
                is_loop: false
            })
        } else {
            that.setData({
                is_loop: true
            })
        }
    },
   
    // 上一首
    prev: function () {
        let that = this

        if (that.data.audio_article.preArticleId != 0) {
            wx.redirectTo({
                url: '/pages/audio_article/audio_article?articleId=' +
                    that.data.audio_article.preArticleId
            })
        }
    },
    // 下一首
    next: function () {
            let that = this

        if (that.data.audio_article.nextArticleId != 0) {
            wx.redirectTo({
                url: '/pages/audio_article/audio_article?articleId=' +
                    that.data.audio_article.nextArticleId
            })
        } else { // 如果是最後一首
            that.setData({
                is_play: false,
                slider_value: 0,
                current_process: '00:00',
                is_ended: true
            })
            AUDIO.is_play = false
        }
    },
    onUnload: function () {
        // 動態切換懸浮按鈕的動態
        if (AUDIO.is_play) {
            APP.globalData.is_active = true
        } else {
            APP.globalData.is_active = false
        }
    }   
})
// 時間格式化
function format(t) {
    let time = Math.floor(t / 60) >= 10 ? Math.floor(t / 60) : '0' + Math.floor(t / 60)

    t = time + ':' + ((t % 60) / 100).toFixed(2).slice(-2)
    return t
}
// 音訊播放
function audio_background_play(response) {
    AUDIOMANAGER.src = response.urlCompressed ? response.urlCompressed : response.audioLink // 音訊的資料來源,預設為空字串,當設定了新的 src 時,會自動開始播放 ,目前支援的格式有 m4a, aac, mp3, wav
    AUDIOMANAGER.title = response.articleName // 音訊標題
    AUDIOMANAGER.epname = response.lessonName // 專輯名
    AUDIOMANAGER.singer = '****' // 歌手名
    AUDIOMANAGER.coverImgUrl = response.poster // 封面圖url
}
複製程式碼
  • app.js
  globalData: {
    userInfo: null,
      global_bac_audio_manager: {
          manage: wx.getBackgroundAudioManager(),
          is_play: false,
          id: '',
          play_time: '',
          article_id: '',
      }
  }
複製程式碼

總結: 在IOS端 背景音訊播放必須設定title 才可以播放

更多文章關注 : https://www.cnblogs.com/luxiaoyao/

相關文章