Что может сделать функцию отмены привязки jQuery работать не так, как ожидалось? - PullRequest
2 голосов
/ 02 июня 2011

Посмотрите на следующий код (дополнительно вам понадобятся jquery.js , jquery.viewport.js и jquery.scrollTo.js ) .

Поведение, которое я ожидаю от этого сценария, заключается в том, что всякий раз, когда я прокручиваю страницу, красные строки (<tr> элементы с классом alwaysVisible) должны быть вставлены непосредственно под самой верхней видимой строкой (<tr> элемент) этой таблицы. Затем необходимо прокрутить страницу, чтобы первая из этих красных строк появилась «точно» в верхней части области просмотра. На самом деле происходит то, что makeVisibleWhatMust(); вызывается неоднократно, пока я не достигну конца страницы. Я думал, что $(window).unbind('scroll'); удержит makeVisibleWhatMust(); от повторного вызова, но, очевидно, это не сработает.

Есть идеи, почему?

Вот JavaScript, который я написал:

function makeVisibleWhatMust()
{
  $('#testContainer').text( $('#testContainer').text() + 'called\n');
  $('table.scrollTable').each
  (
    function()
    {
      var table = this;
      $($('tr.alwaysVisible', table).get().reverse()).each
      (
    function()
    {
      $(this).insertAfter( $('tr:in-viewport:not(.alwaysVisible)', table)[0] );
    }
      );
      $(window).unbind('scroll');
      $(window).scrollTo( $('tr.alwaysVisible')[0] );
      $(window).bind('scroll', makeVisibleWhatMust);
    }
  );
}

$(document).ready
(
  function()
  {
    $(window).bind('scroll', makeVisibleWhatMust);
  }
);

А вот HTML-страница для тестирования:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Scroll Tables Test Page</title>

    <script type="text/javascript" src="jQuery.js"></script>
    <script type="text/javascript" src="jquery.viewport.js"></script>
    <script type="text/javascript" src="jquery.scrollTo.js"></script>
    <script type="text/javascript" src="scrollTable.js"></script>

    <style type="text/css">
      table th, table td
      {
    border: 1px solid #000;
    padding: .3em;
      }
      .alwaysVisible
      {
    background: #F66;
      }
    </style>
  </head>
  <body>
    <table class="scrollTable">
      <thead>
    <tr class="alwaysVisible">
      <th>Row name</th>
      <th>Content</th>
    </tr>
    <tr class="alwaysVisible">
      <th>Row 2</th>
      <th>Row 2</th>
    </tr>
      </thead>
      <tbody>
    <script type="text/javascript">
      for(var i = 0; i < 50; ++i)
      {
        document.writeln("<tr><td>Row " + i + "</td><td>Content</td></tr>");
      }
    </script>
      </tbody>
      <tfoot>
    <tr>
      <td>Footer</td>
      <td>Footer 2</td>
    </tr>
      </tfoot>
    </table>
    <div id="testContainer">TEST CONTAINER</div>
  </body>
</html>

1 Ответ

0 голосов
/ 02 июня 2011

Я думаю, что ваша проблема в том, что scrollTo использует animate:

// From the plugin's source
function animate( callback ){  
    $elem.animate( attr, duration, settings.easing, callback && function(){  
        callback.call(this, target, settings);  
    });  
};

И animate использует таймер для выполненияанимация.В результате .scrollTo вернется до завершения прокрутки, и вы перепривязаете обработчик прокрутки, пока scrollTo все еще прокручивает.Отсюда и события, когда вы их не ожидаете.

Простое решение - использовать флаг, чтобы сообщить makeVisibleWhatMust, что scrollTo прокручивается, и использовать обратный вызов scrollTo, чтобы сбросить флаг, когдаготово, что-то вроде этого:

function makeVisibleWhatMust() {
  // Ignore the event if we're doing the scrolling.
  if(makeVisibleWhatMust.isScrolling)
    return;
  $('#testContainer').text( $('#testContainer').text() + 'called\n');
  $('table.scrollTable').each(function() {
      var table = this;
      $($('tr.alwaysVisible', table).get().reverse()).each(function() {
        $(this).insertAfter( $('tr:in-viewport:not(.alwaysVisible)', table)[0] );
      });
      makeVisibleWhatMust.isScrolling = true;
      $(window).scrollTo($('tr.alwaysVisible')[0], {
        onAfter: function() { makeVisibleWhatMust.isScrolling = false; }
      });
    }
  );
}
makeVisibleWhatMust.isScrolling = false;

И вот живая версия, которая, кажется, работает: http://jsfiddle.net/ambiguous/ZEx6M/1/

...