已结束的侦听器无法正常工作

时间:2016-12-10 23:17:51

标签: javascript html

这个函数只有在数组 defaultArrayMelody 是不同的数字时才会有效 - 一个接一个 - 我的意思是:[5,3,4,2] - 它有效, [5,3,3,2] - 它不起作用。

我怀疑'已结束'的侦听器执行了两次,并为该元素添加了两个事件侦听器。然后该函数循环,它不能按我的意愿工作。如何限制听众的追求?

Java脚本:

function playDefault() {
const defaultArrayMelody = [70, 71, 69, 70];
const audio = defaultArrayMelody.map(el => document.querySelector(`audio[data-key="${el}"]`));


for (let i = 0 ; i < defaultArrayMelody.length; ++i) {
    audio[i].addEventListener('ended', () => {

        const index = i + 1;
        if (index > audio.length-1) return false;
        audio[index].play();            
    });
}

audio[0].play();
}

document.querySelector(`#playDefault`).addEventListener('click', playDefault);

HTML:

<button class="button" id="playDefault">Play Default</button>
<audio data-key="67" src="sounds/c1.wav"></audio>...

1 个答案:

答案 0 :(得分:0)

一旦结束听众发射,你需要移除它,所以它不会再被解雇

但是,你添加事件监听器的方式(基本上都是一次)意味着你已经多次为多次播放的音频添加了多个监听器,所以如果重复的音频不是。在阵列中的最后一个,毫无疑问,你会得到一些问题

理想的解决方案是仅在音频启动时添加侦听器,并在ended事件触发后删除侦听器。

  

这些答案包括评论中的可选&#34;暂停&#34;在音频元素播放之间 - 这由defaultArrayMelody

中的否定数字表示
function playDefault() {
    const defaultArrayMelody = [70, 71, -1000, 69, 70];
    const audio = defaultArrayMelody.map(el => el < 0 ? -el : document.querySelector(`audio[data-key="${el}"]`));

    var playAudio = function(index) {
        if (audio[index]) {
            var listener = function() {
                this.removeEventListener('ended', listener);
                playAudio(index + 1);
            };
            if (typeof audio[index] == 'number') {
                setTimeout(() => playAudio(index + 1), audio[index]);
            } else {
                audio[index].addEventListener('ended', listener);
                audio[index].play();
            }
        }
    };
    playAudio(0);
}
document.querySelector(`#playDefault`).addEventListener('click', playDefault);

另一种方法是使用Promise

function playDefault() {
    const defaultArrayMelody = [70, 71, -1000, 69, 70];
    const audio = defaultArrayMelody.map(el => el < 0 ? -el : document.querySelector(`audio[data-key="${el}"]`));

    audio.reduce((prev, item) => prev.then(() => new Promise(resolve => {
        var listener = function listener() {
            this.removeEventListener('ended', listener);
            resolve();
        };
        if (typeof item== 'number') {
            setTimeout(resolve, item); // item is millseconds
        } else {
            item.addEventListener('ended', listener);
            item.play();
        }
    })), Promise.resolve());
}
document.querySelector(`#playDefault`).addEventListener('click', playDefault);

在这里,您可能不会删除事件监听器,因为事件监听器唯一能做的就是解决承诺 - 一旦解决了承诺,就无法再解决(或拒绝) - 从而确保序列只按顺序播放一次。但是,在上面的代码中我包含了removeEventListener ...没有它,代码看起来像

function playDefault() {
    const defaultArrayMelody = [70, 71, -1000, 69, 70];
    const audio = defaultArrayMelody.map(el => el < 0 ? -el : document.querySelector(`audio[data-key="${el}"]`));

    audio.reduce((prev, item) => prev.then(() => new Promise(resolve => {
        if (typeof item== 'number') {
            setTimeout(resolve, item); // item is millseconds
        } else {
            item.addEventListener('ended', resolve);
            item.play();
        }
    })), Promise.resolve());
}
document.querySelector(`#playDefault`).addEventListener('click', playDefault);