Как мне заставить эту задержку анимации jquery работать должным образом? - PullRequest
2 голосов
/ 08 ноября 2010

У меня есть 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'> были скрыты после загрузки страницы, а затем для показа slideDown, когда указатель мыши входит в строку выше. Я хочу, чтобы строка .slide оставалась в поле зрения, пока указатель мыши остается в строке выше или в строке .slide (содержится в тегах <tbody>). Затем я хочу, чтобы строка .slide выскользнула из поля зрения, когда мышь оставляет одну из строк в тегах <tbody>. Мне удалось сделать это успешно с помощью следующего кода.

<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> к следующему эффекты в то же время, кажется, что строка заголовка между ними движется вверх (надеюсь, это имеет какой-то смысл). Я пробовал несколько способов сделать это, но безуспешно. Мои лучшие усилия заключаются в следующем:

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 ]

1 голос
/ 08 ноября 2010

Попробуйте использовать плагин hoverIntent вместо попытки имитировать "задержку зависания" с mouseenter и mouseleave. Я почти всегда использую hoverIntent вместо простого hover.

0 голосов
/ 08 ноября 2010

ОК, я наконец решил это (и многому научился).

Код, как указано, работает, если я заменю div на div2 в части кода, оставляемой мышью. Использование одного и того же имени переменной для вверх и вниз привело к тому, что анимация не произошла. Единственная проблема заключается в том, что, если бы я быстро переместил несколько строк, я все равно получил бы неожиданные результаты, так как это имя одной переменной использовалось и злоупотребляло.

Мое решение - предоставить каждой строке .slide уникальный идентификатор, например, так:

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

Затем я использую этот идентификатор для генерации динамического имени переменной, используя 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, но вместо этого я иду в спортзал).

...