“timeupdate”事件功能在重新绑定后两次射击

时间:2013-04-03 17:20:21

标签: jquery javascript-events html5-audio

我在jQuery中遇到<audio>元素的timeupdate事件有问题(我使用的是1.7.1版本)。我的目标是将一个函数绑定到它,然后取消绑定它,然后再绑定它。它在Firefox,谷歌浏览器和Internet Explorer 10中的表现并不像我期望的那样。火狐和谷歌浏览器的行为相同,但Internet Explorer 10表现不一样(惊喜!)。当然,我希望它能在这三种方式中发挥作用。

我认为问题最好用代码本身来描述(问题的细节在HTML的第二个<p>中):

HTML

<p>Click the circle on the right whose color matches the circle on the left. Do this four times.</p>

<p>Clicking the incorrect color will play audio. As soon as the singing starts, a message is logged to the console. This works the first time, but after that, it starts happening twice.</p>

<div class="goal"></div>
<div class="choices"></div>

<audio id="audio-try_again" preload="auto">
    <source src="try_again.ogg">
    <source src="try_again.mp3">
</audio>

CSS

.goal, .choices {
    float: left;
    width: 50%;
}

的JavaScript

$.randomize = function(arr) {
    for (var j, x, i = arr.length; i; j = parseInt(Math.random() * i, 10), x = arr[--i], arr[i] = arr[j], arr[j] = x);
    return arr;
};

function factorial(num) {
    var rval = 1;

    for (var i = 2; i <= num; i++) {
        rval = rval * i;
    }

    return rval;
}

function generate_objects() {
    this_pair = get_object_pair();

    if (used_pairs.length < total_permutations) {
        while ($.inArray(this_pair, used_pairs) > -1) {
            this_pair = get_object_pair();
        }
    }
    else {
        used_pairs = [];
    }

    used_pairs.push(this_pair);

    objects = this_pair.split('|');

    object_to_find = objects[0];
    other_object = objects[1];

    $('.goal').html('<a href="javascript:void(0);"><img src="' + images[object_to_find] + '" alt=""></a>');
    $('.choices').html('');

    choices = [
        $('<a href="javascript:void(0);" class="correct"><img src="' + images[object_to_find] + '" alt=""></a>'),
        $('<a href="javascript:void(0);" class="incorrect"><img src="' + images[other_object] + '" alt=""></a>')
    ];

    $.randomize(choices);

    $.each(choices, function(index, value) {
        $('.choices').append(value);
    });

    $('#audio-try_again').on('timeupdate', function() {
        if (try_again_audio_element.currentTime >= 5) {
            $(this).off('timeupdate');

            console.log('Highlight the correct image.');

            $('.correct').animate({opacity: 0.25}, 200, function() {
                $(this).animate({opacity: 1}, 200, function() {
                    $('.correct').animate({opacity: 0.25}, 200, function() {
                        $(this).animate({opacity: 1}, 200);
                    });
                });
            });
        }
    });

    $('.goal, .choices').fadeIn();
}

function get_object_pair() {
    object_to_find = other_object = get_random_index();

    while (other_object == object_to_find) {
        other_object = get_random_index();
    }

    return object_to_find + '|' + other_object;
}

function get_random_index() {
    return Math.floor(Math.random() * total_images);
}

function question_answered() {
    if (correct_answers == 4) {
        alert('You have correctly answered four questions.');
    }
    else {
        $('.goal, .choices').fadeOut(function() {
            $('#audio-try_again').off('timeupdate');

            setTimeout(generate_objects, 200);
        });
    }
}

$(document).ready(function() {
    correct_answers = 0;

    images = [
        'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAcUlEQVR42qXT0QnAIAxFUUfJNJlOp+gwWUfIAOkTUpBAC/V9nI9KuKDV1iIqhQEGM1muaZ3fPwQ6OMQLzxmpAYGrDH+5QPZAh/ipPwEFPwg4aMvDiUNjBYwI2ApMIjDpAL0F+hDp30heJP4q84+Jfs43txnFT7FsW/cAAAAASUVORK5CYII=',
        'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAcUlEQVR42qWT0QnAIAxEHSXTZDqdosNknYADpCekIJZW2kPeh3I8TIwl7ktBAwY8sTzTNT1vBFTQQTzQMyOrQMCRoS2ZlVlQQXykXgJ9u/amHC3ZnPhJGwIjBDYETgicFtAl0E2kn5EcJH6U+c9Ef+cTtijFT/BuGVoAAAAASUVORK5CYII=',
        'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAcUlEQVR42qWT0QnAIAxEHSXTOF2dosNkHcEB0hMOwUAp9j7eh3J5YExKRMlU0ICDTpx3NWW3g4ELDBAvDGYsCwzcDH3CrC0BrXECa9abx6mANbWwOfGTNgUuCHwKuiDoskB+gtxE+RvFQdJHWV8meZ0ftTfFT731dloAAAAASUVORK5CYII=',
        'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAa0lEQVR42qXT0QnAIAwE0IziNE6XTOEwWSeQAex9hFKKbaknvB+JB1Eji9XBwCGK116Xl9VAIWE+yKppq8PjLPw27iEK8ye99pwbAVlnxWBuMhAnAhwkiICgA+gW6Eukn5H8SPxX5oeJHucDimXHMWd8ov0AAAAASUVORK5CYII='
    ];

    total_images = images.length;
    total_permutations = factorial(total_images) / factorial(total_images - 2);

    try_again_audio_element = $('#audio-try_again')[0];

    $(document).on('click', '.correct', function() {
        if (!$(this).hasClass('disabled')) {
            $('.correct, .incorrect').addClass('disabled');

            correct_answers++;
            question_answered();
        }
    }).on('click', '.incorrect', function() {
        if (!$(this).hasClass('disabled')) {
            $('.correct, .incorrect').addClass('disabled');

            try_again_audio_element.play();
        }
    });

    $('#audio-try_again').on('ended', function() {
        question_answered();
    });

    used_pairs = [];
    generate_objects();
});

演示:http://jsfiddle.net/j8LXE/

有什么想法吗?

1 个答案:

答案 0 :(得分:2)

看起来问题就是这个问题:

$('.goal, .choices').fadeOut(function() {
   $('#audio-try_again').off('timeupdate');
   setTimeout(generate_objects, 200);
});

选择器$('.goal, .choices')将返回一个包含两个元素的jQuery集合,这意味着将调用两次回调函数(每个匹配元素一次)。

根据您的具体应用,快速而肮脏的方法是:

$('.goal, .choices').fadeOut(function() {
   if ( $(this).is('.goal') ) return;
   $('#audio-try_again').off('timeupdate');
   setTimeout(generate_objects, 200);
});

基本上,只执行一次回调中的内容。