1

我正在制作一个包含游戏列表的页面。我添加了按类型过滤游戏的单选按钮。当用户单击类型过滤器时,我正在使用 jQuery 优雅地淡入淡出游戏列表。

问题是每次单击单选按钮时,游戏列表都会尴尬地淡入淡出两次。见:http: //jsfiddle.net/animeguy99/pZKda/1/

这是我正在使用的脚本:

$('input[name$="group1"]').click(function(){
    var radio_value = $(this).val();    
    if(radio_value=='Adventure') {
      $('#games div').fadeOut('slow', function(){
            $('#games .adv').fadeIn();
      });
    }
    else if(radio_value=='Puzzle') {
      $('#games div').fadeOut('slow', function(){
            $('#games .puz').fadeIn();
      });
    }
    else if(radio_value=='Shooter') {
      $('#games div').fadeOut('slow', function(){
            $('#games .sho').fadeIn();
      });
    }
    else if(radio_value=='All') {
      $('#games div').fadeOut('slow', function(){
            $('#games div').fadeIn();
      });
    }
});

我有 DIV 类声明的流派类型。因此,每次用户单击收音机时,我都会淡出所有 DIV(游戏),然后按 DIV 类淡入请求的类型。

当我四处搜索时,类似的案例表明这可能是父母/孩子的问题。但我很困惑如何将它与我的脚本联系起来。

我在看什么?

4

5 回答 5

1

当有多个元素被淡化时,回调函数.fadeOut()并不会像您期望的那样工作。.fadeIn()回调不仅被调用一次,而且对每个元素都被调用。

如果您console.log()在其中一个.fadeOut()回调中调用,您会看到它被记录了多次。(Chrome 开发者工具将其折叠成一个日志条目,左侧有一个数字。)

http://jqapi.com/#p=fadeOut

回调函数

如果提供,则在动画完成后触发回调。这对于将不同的动画按顺序串在一起很有用。回调没有发送任何参数,但它被设置为动画的 DOM 元素。如果为多个元素设置了动画,请务必注意,每个匹配的元素都会执行一次回调,而不是对整个动画执行一次。

从 jQuery 1.6 开始,.promise() 方法可以与 deferred.done() 方法结合使用,以便在所有匹配元素都完成动画时对整个动画执行单个回调(参见 .promise 示例())。

这是.promise()用于删除重复回调的代码版本。它还结合了 j08691 的建议,即从 fadeOut 中排除您将要淡入的元素:

var groups = {
    Adventure: '.adv',
    Puzzle: '.puz',
    Shooter: '.sho',
    All: 'div'
};

function fade( group ) {
    $('#games div')
        .not(group)
        .fadeOut()
        .promise()
        .done( function() {
            console.log( group );
            $('#games ' + group).fadeIn();
        });
}

$('input[name$="group1"]').click(function () {
    fade( groups[ $(this).val() ] );
});

通过将重复的代码合并到一个函数中,此代码也大大简化了原始代码。最后,我离开了 console.log() 来查看正在进行的调用。

还有一些关于 HTML 的评论:除非您正在编写 XHTML,否则您不需要使用<br />,我希望您没有这样做。<br>很好。更重要的是,您应该<label>在单选按钮标签上使用标签,以便整个标签都是可点击的:

<label><input type="radio" name="group1" value="All" checked>Show All</label><br>
<label><input type="radio" name="group1" value="Adventure">Adventure</label><br>
<label><input type="radio" name="group1" value="Puzzle">Puzzle</label><br>
<label><input type="radio" name="group1" value="Shooter">Shooter</label>

这是一个更新的 jsfiddle

这里还有其他简化的机会。单选按钮中的属性是否要求value为特定字符串“All”、“Adventure”等?如果没有,您可以简单地将组选择器直接放在value属性中:

<label><input type="radio" name="group1" value="div" checked>Show All</label><br>
<label><input type="radio" name="group1" value=".adv">Adventure</label><br>
<label><input type="radio" name="group1" value=".puz">Puzzle</label><br>
<label><input type="radio" name="group1" value=".sho">Shooter</label>

然后将 JavaScript 代码简化为:

function fade( group ) {
    $('#games div')
        .not(group)
        .fadeOut()
        .promise()
        .done( function() {
            console.log( group );
            $('#games ' + group).fadeIn();
        });
}

$('input[name$="group1"]').click(function () {
    fade( $(this).val() );
});

最新的 jsfiddle

另一个更新...正如 Alex 在评论中指出的那样,当您在 Show All 和特定类型之间来回单击时,此版本的代码会导致块跳来跳去。

这是由代码中的这一行引起的:

        .not(group)

删除该行可以提供更平滑的过渡,如更新后的 jsfiddle所示。

于 2013-03-20T17:06:03.600 回答
1

试试这个小提琴。问题在于您的 jQuery Selector $('#games div')。您的选择指向多个 DOM 元素。所以它将fadeOut()为范围内的每个元素运行,然后在每个元素的回调中运行fadeIn()。添加一个额外的选择器将确保它只运行一次。

$('#games div').filter(":visible")

添加.filter(":visible")限制将确保只有那些可见的应该淡出(如果不使用过滤器,而不是选择的任何元素被隐藏,它将fadeIn()立即触发)。它还将确保fadeIn()仅在选择中所有可见的元素现在都隐藏后才运行。

jsfiddle

于 2013-03-20T17:06:45.023 回答
0

你需要先排除这组元素淡出(通过类似的东西.not('.puz')),否则 jQuery 会先让它们再次可见,然后再淡出。试试这个(为清楚起见添加了延迟):

$('input[name$="group1"]').click(function () {
    var radio_value = $(this).val();
    if (radio_value == 'Adventure') {
        $('#games div').not('.adv').fadeOut(3000,function () {
            $('#games .adv').fadeIn(3000);
        });
    } else if (radio_value == 'Puzzle') {
        $('#games div').not('.puz').fadeOut(3000,function () {
            $('#games .puz').fadeIn(3000);
        });
    } else if (radio_value == 'Shooter') {
        $('#games div').not('.sho').fadeOut(3000,function () {
            $('#games .sho').fadeIn(3000);
        });
    } else if (radio_value == 'All') {
        $('#games div').fadeOut(3000, function () {
            $('#games div').fadeIn(3000);
        });
    }
});

jsFiddle 示例

于 2013-03-20T16:57:31.730 回答
0

问题是,当您在几个元素上调用 fadeOut 时,它会被调用多次。并且触发淡入的回调被调用相同的次数。你不需要那个。只有在所有的淡出完成后,您才需要开始调用淡入。

其中一种方法是使用 $.when .. $ done 序列:

$.when(
   $('#games div').fadeOut('slow');

).done(function() {
   $('#games .adv').fadeIn();
});

http://api.jquery.com/jQuery.when/
http://api.jquery.com/deferred.done/

于 2013-03-20T17:21:52.710 回答
0

如果您使用 html5 数据类型属性,则很简单。结帐jsfiddle

于 2013-03-20T23:29:55.083 回答