現在很多移動端要求audio播放必需由使用者的事件觸發,否則就劫持。實際應用中經常會出現JS網路請求通過返回的結果來決定播放什麼音訊,在移動端是不允許的。

當移動需要通過網路請求回撥來播放音訊時,就得做點準備工作,具體程式碼如下:

載入準備處理

/**
 * 迴圈處理
 * @param {Object} data
 * @param {Function} callback
 * @returns {undefined}
 */
function each(data, callback) {
    if (typeof data === `object`) {
        if (data.length) {
            for (var key = 0; key < data.length; key++) {
                if (callback(key, data[key]) === false) {
                    break;
                }
            }
        } else {
            for (var key in data) {
                if (callback(key, data[key]) === false) {
                    break;
                }
            }
        }
    }
}

/**
 * 播放音訊
 * @param {String} name
 * @returns {undefined}
 */
function audioPaly(name) {
    each(name.split(/s+/), function (_, name) {
        if (audioPaly.lists[name]) {
            audioPaly.lists[name].play();
        }
    });
}
audioPaly.lists = {};

/**
 * 就緒音訊處理
 * @returns {undefined}
 */
function audioReady() {
    var audio;
    while ((audio = audioReady.lists.pop())) {
        audio.play();
        audio.pause(); //直接暫停,可快速再播放
    }
}
audioReady.lists = [];

/**
 * 載入音訊
 * @param {String} path
 * @param {Function} callback
 * @returns {undefined}
 */
function loadAudio(path, callback) {
    var audio = create(`audio`, {preload: `load`});
    each({`ogg`: `ogg`, `mp3`: `mpeg`, `wav`: `wav`}, function (name, type) {
        audio.appendChild(create(`source`, {src: `/audio/` + path + `.` + name, type: `audio/` + type}));
    });
    addEvent(audio, `loadedmetadata`, function () {
        audioPaly.lists[path] = {
            play: function () {//播放
                    audio.currentTime = 0; //這個用途不大,相容處理
                                if (!audio.ended) {
                                     audio.load(); //重新載入,相容處理,同時也可以快速開始播放
                                }
                audio.play();
            }
        };
        audioReady.lists.push(audio);
        callback && callback();
    });
    loadAudio.frame.appendChild(audio);
}
/**
 * 建立元素
 * @param {String} elem
 * @param {Object} addAttr
 * @returns {Element}
 */
function create(elem, addAttr){
    var Elem = document.createElement(elem);
    for(var key in addAttr){
        Elem.setAttribute(key, addAttr[key]);
    }
    return Elem;
}

//載入音訊
loadAudio(`test`);

使用者事件觸發處理

//繫結使用者可觸發元素點選事件
element.addEventListener(`click`, function(){
    audioReady();//音訊觸發就緒處理,用於回撥再次播放
    //網路請求程式碼
    ....
        //網路回撥器
        function (){
            audioPaly(`test`);//播放處理
        }
    ....
});

準備的音訊檔案(為什麼準備多個就不多說了,具體看面向的終端支援音訊格式來定)

/audio/test.mp3

/audio/test.ogg

/audio/test.wav

這段程式碼並不複雜,只是利用了移動端限制中的一點點許可,當在使用者觸發事件中播放了,那麼在後續的操作的就可以再次播放。

只要我們在使用者觸發後播放音訊並及時暫停或靜音就可以不被聽到音訊,然後在網路請求回撥中再次操作播放即可實現,動態播放。