如何使此jquery动画延迟正常工作?

时间:2010-11-08 05:52:26

标签: javascript jquery settimeout

我有一个html表,我试图用jQuery添加一些动画。我非常接近我想要的但有一个悬而未决的问题。我将尝试描述我正在做的事情,尽可能减少表格和脚本的版本。

该表定义如下;

<table>
  <tbody class="group">
    <tr>First</tr>
    <tr class='slide'><div class='hidden'>Surprise!</div></tr>
  </tbody>
  <tbody class="group">
    <tr>Second</tr>
    <tr class='slide'><div class='hidden'>Surprise!</div></tr>
  </tbody>
  <tbody class="group">
    <tr>Third</tr>
    <tr class='slide'><div class='hidden'>Surprise!</div></tr>
  </tbody>
</table>

我想要的效果是一旦页面加载就隐藏所有<tr class='slide'>行,然后当鼠标指针进入上面的行时滑动到视图中。只要鼠标指针保留在上面的行或.slide行(包含在<tbody>标记内)中,我希望.slide行保持在视图中。然后,当鼠标离开<tbody>标记内的任一行时,我希望.slide行滑出视图。我已成功使用以下代码完成此操作。

<script>

$(function() {
  hideRows();
  setupEventHandlers(); 
});

function hideRows() {
  $("div.hidden").each(function() {
    $(this).hide();
});
};
//The hideRows function is much more complicated in my actual page
//as I have to calculate the div height prior to hiding so it animates
//correctly. That's why I don't just set display:none; in the stylesheet.

function setupEventHandlers() {
  $('.group').mouseenter(function() {
    var tr = $(this).children('tr.slide');
    tr.find("div.hidden").each(function() {
      $(this).slideDown();
    });
  });
  $('.group').mouseleave(function() {
    var tr = $(this).children('tr.slide');
    tr.find("div.hidden").each(function() {
      $(this).slideUp();
    });
});
};
//note that I have to animate the div rather than the tr
//as slidedown and slideup don't work on table rows

</script>

虽然这有效,但它有一个问题,即如果你在多行上运行鼠标,它会设置一个巨大的摇晃混乱,可以运行很长时间,直到所有的动画完成。我想要做的是添加超时,以便在输入<tbody>后动画不会开始一秒左右。如果鼠标在触发动画之前离开<tbody>,则应取消它。当鼠标指针离开<tbody>时,slideUp效果也应该延迟相同的数量 - 我希望最后一个要求是,如果你从一个<tbody>向下移动到下一个slideDown和slideUp效果会在同一时间发生,所以看起来他们之间的标题行正在向上移动(我希望这有点意义)。我尝试了几种方法,但都没有成功。我的最大努力如下:

var timer;

function setupEventHandlers() {
  $('.group').mouseenter(function() {
    var tr = $(this).children('tr.slide');
    tr.find("div.hidden").each(function() {
      div = $(this);
      timer = setTimeout("div.slideDown();",1000);
    });
  });
  $('.group').mouseleave(function() {
    var tr = $(this).children('tr.slide');
    tr.find("div.hidden").each(function() {
      clearTimeout(timer);
      div = $(this);
      setTimeout("div.slideUp();",1000);
    });
});
};

几乎有效。如果我快速进入然后离开一行,则不会发生动画。如果我输入一行并等待1秒钟,则下一行按计划向下滑动。如果我然后将行退出到一侧,则隐藏行将按计划在1秒后向上滑动。但是,如果我进入下面的行,那么事情就出错了。新行在1秒后按预期滑入视图,但旧行仍然存在。我的假设是我的计时器变量被无意中销毁了。我尝试通过一组定时器并为每一行分配一个特定的定时器来更加具体地了解该过程,但这没有任何区别。 Javascript不是我强大的西装,你可能会说。

2 个答案:

答案 0 :(得分:1)

尝试使用hoverIntent插件,而不是尝试使用mouseentermouseleave来模拟“延迟悬停”。我几乎总是使用hoverIntent而不是简单的悬停。

答案 1 :(得分:0)

好的,我终于解决了这个问题(也学到了很多东西)。

如果我在代码的mouseleave部分用div2替换div,则提供的代码有效。使用相同的变量名称进行向上和向下操作会导致动画不会发生。唯一的问题是,如果我快速地过多次行,我仍会得到意想不到的结果,因为这个变量名被过度使用和滥用。

我的解决方案是为每个.slide行提供一个如此唯一的ID;

<tr class='slide'><div class='hidden'>Surprise!</div></tr>

然后我使用此id使用eval生成动态变量名称,并在setTimeout中的字符串中引用它。我的最终代码看起来像这样。

var timer;

function setupEventHandlers() {
  $('.group').mouseenter(function() {
    var tr = $(this).children('tr.slide');
    tr.find("div.hidden").each(function() {
      id = this.id;
      eval("divdown_" + id + " = $(this);");
      downstring = "divdown_" + id + ".slideDown();";
      timer = setTimeout(downstring,1000);
    });
  });
  $('.group').mouseleave(function() {
    var tr = $(this).children('tr.slide');
    tr.find("div.hidden").each(function() {
      clearTimeout(timer);
      id = this.id;
      eval("divup_" + id + " = $(this);");
      upstring = "divup_" + id + ".slideUp();";
      setTimeout(upstring,1000);
    });
});
};

并且工作得很漂亮(至少在firefox中,我太害怕尝试IE了 - 我要去健身房了。)