复杂的连续滚动循环

Complex continuous scroll loop

我的代码类似于:

<div id='right-column'>
    <div id='results'>
        <div id='result1>
            <div class='main'></div>
            <div class='details'></div>
        </div>
        <!-- ... -->
        <div id='result50>
            <div class='main'></div>
            <div class='details'></div>
        </div>
    </div>
</div>

如果 #results scrollHeight 大于 #right-column height,我想创建一个连续的滚动循环。
在这种情况下,滚动到 #result50 将显示 #result1,滚动到 #result1 之前将显示 #result50.

我无法 .append() 将第一个 child 排到底部,因为在某些情况下可以在列的顶部和底部看到 result 的一部分。
我无法复制 result 除非我检测 .details 是否为 unfolded/folded.
当用户展开 .details div 时,result 的高度会发生变化,这一事实使其变得更加复杂......

这是一个连续滚动循环的例子(2 列):

$(document).ready(function() {
  var num_children = $('#up-left').children().length;
  var child_height = $('#up-left').height() / num_children;
  var half_way = num_children * child_height / 2;
  $(window).scrollTop(half_way);

  function crisscross() {
    $('#up-left').css('bottom', '-' + window.scrollY + 'px');
    $('#down-right').css('bottom', '-' + window.scrollY + 'px');
    var firstLeft = $('#up-left').children().first();
    var lastLeft = $('#up-left').children().last();
    var lastRight = $('#down-right').children().last();
    var firstRight = $('#down-right').children().first();

    if (window.scrollY > half_way ) {
      $(window).scrollTop(half_way - child_height);
      lastRight.appendTo('#up-left');
      firstLeft.prependTo('#down-right');
    } else if (window.scrollY < half_way - child_height) {
      $(window).scrollTop(half_way);
      lastLeft.appendTo('#down-right');
      firstRight.prependTo('#up-left');
    }
  }

  $(window).scroll(crisscross);
});
div#content {
  width: 100%;
  height: 100%;
  position: absolute;
  top:0;
  right:0;
  bottom:0;
  left:0;
}
#box {
  position: relative;
  vertical-align:top;
  width: 100%;
  height: 200px;
  margin: 0;
  padding: 0;
}
#up-left {
  position:absolute;
  z-index:4px;
  left: 0;
  top: 0px;
  width: 50%;
  margin: 0;
  padding: 0;
}
#down-right {
  position:fixed;
  bottom: 0px;
  z-index: 5px;
  left: 50%;
  width: 50%;
  margin: 0;
  padding: 0;
}
h1 {margin: 0;padding: 0;color:#fff}
.black {background: black;}
.white {background: grey;}
.green {background: green;}
.brown {background: brown;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>

<div id="content">
  <div id="up-left">
    <div id="box" class="brown">
      <h1>ONE</h1>
    </div>
    <div id="box" class="black">
      <h1>TWO</h1>
    </div>
    <div id="box" class="white">
      <h1>THREE</h1>
    </div>
    <div id="box" class="black">
      <h1>FOUR</h1>
    </div>
    <div id="box" class="white">
      <h1>FIVE</h1>
    </div>
    <div id="box" class="black">
      <h1>SIX</h1>
    </div>
  </div><!-- #up-left -->
  <div id="down-right">
    <div id="box" class="white">
      <h1>SIX</h1>
    </div>
    <div id="box" class="black">
      <h1>FIVE</h1>
    </div>
    <div id="box" class="white">
      <h1>FOUR</h1>
    </div>
    <div id="box" class="black">
      <h1>THREE</h1>
    </div>
    <div id="box" class="white">
      <h1>TWO</h1>
    </div>
    <div id="box" class="green">
      <h1>ONE</h1>
    </div>
  </div><!-- #down-right -->
</div><!-- .content -->
(fiddle: http://jsfiddle.net/franckl/wszg1d6c/)

任何 hint/ideas 我该怎么做?

根据滚动方向将项目移动到顶部或底部

您可以使用 jQuery 的 .append().prepend() 移动 项而无需克隆它们。

您将使用与延迟加载 (AJAX) 无限滚动类似的技术,但在这种情况下,您希望处理向上和向下滚动,而不是从服务器加载新内容,您只是在回收列表中现有的 DOM 个元素。

下面我演示一种技术。我将滚动位置存储在元素的 .data 缓存中,以便在检测滚动方向时轻松检索。我选择检测滚动方向以避免预先进行不必要的变量分配以提高性能。否则,您将获取元素并为不会在该方向发生的滚动事件进行数学运算。

滚动处理程序:

$('#right-column').on('scroll', function (e) {
    var $this = $(this),
        $results = $("#results"),
        scrollPosition = $this.scrollTop();

    if (scrollPosition > ($this.data('scroll-position') || 0)) {
        // Scrolling down
        var threshold = $results.height() - $this.height() - $('.result:last-child').height();

        if (scrollPosition > threshold) {
            var $firstResult = $('.result:first-child');
            $results.append($firstResult);
            scrollPosition -= $firstResult.height();
            $this.scrollTop(scrollPosition);
        }
    } else {
        // Scrolling up
        var threshold = $('.result:first-child').height();
        if (scrollPosition < threshold) {
            var $lastResult = $('.result:last-child');
            $results.prepend($lastResult);
            scrollPosition += $lastResult.height();
            $this.scrollTop(scrollPosition);
        }
    }
    $this.data('scroll-position', scrollPosition)
});

一个完整的工作示例:

$('#right-column').on('scroll', function (e) {
    var $this = $(this),
        $results = $("#results"),
        scrollPosition = $this.scrollTop();

    if (scrollPosition > ($this.data('scroll-position') || 0)) {
        // Scrolling down
        var threshold = $results.height() - $this.height() - $('.result:last-child').height();
      
       if (scrollPosition > threshold) {
           var $firstResult = $('.result:first-child');
            $results.append($firstResult);
           scrollPosition -= $firstResult.height();
            $this.scrollTop(scrollPosition);
        }
    } else {
        // Scrolling up
        var threshold = $('.result:first-child').height();
        if (scrollPosition < threshold) {
            var $lastResult = $('.result:last-child');
            $results.prepend($lastResult);
           scrollPosition += $lastResult.height();
            $this.scrollTop(scrollPosition);
        }
    }
   $this.data('scroll-position', scrollPosition)
});

$('#results').on('click', '.result', function (e) {
   $(this).find('.details').toggle();
});

$('#newNumber').on('input', function (e) {
    var results = '';
    for (var n = 1; n <= $(this).val(); n++) {
        results += 
          '<div class="result" id="result' + n + '">' +
          '    <div class="main">Result ' + n + '</div>' +
          '    <div class="details">Details for result ' + n + '</div>' +
          '</div>';
    }
   $('#results').html(results);
});
body {
  font-family: sans-serif;
}
h1 {
  font: bold 2rem/1 Georgia, serif;
}
p {
  line-height: 1.5;
  margin-bottom: 1em;
}
label {
  font-weight: bold;
  margin-bottom: 1em;
}
.column {
  box-sizing: border-box;
  float: left;
  width: 50%;
  height: 100vh;
  padding: 1em;
  overflow: auto;
}
#right-column {
  background-color: LemonChiffon;
}
.result {
  padding: 1em;
  cursor: pointer;
}
.result .main {
  height: 2em;
  font-weight: bold;
  line-height: 2;
}
.result .details {
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class=
"column" id="left-column">
  <p>Existing DOM elements are moved to the top or bottom of the list depending on your scroll direction.</p>
  <label>Change the number of results to display
    <input id="newNumber" type="number" value="10" />
</div>
<div class=
"column" id="right-column">
  <div id="results">
    <div id="result1" class="result">
      <div class="main">Result 1</div>
      <div class="details">Details for result 1</div>
    </div>
    <div id="result2" class="result">
      <div class="main">Result 2</div>
      <div class="details">Details for result 2</div>
    </div>
    <div id="result3" class="result">
      <div class="main">Result 3</div>
      <div class="details">Details for result 3</div>
    </div>
    <div id="result4" class="result">
      <div class="main">Result 4</div>
      <div class="details">Details for result 4</div>
    </div>
    <div id="result5" class="result">
      <div class="main">Result 5</div>
      <div class="details">Details for result 5</div>
    </div>
    <div id="result6" class="result">
      <div class="main">Result 6</div>
      <div class="details">Details for result 6</div>
    </div>
    <div id="result7" class="result">
      <div class="main">Result 7</div>
      <div class="details">Details for result 7</div>
    </div>
    <div id="result8" class="result">
      <div class="main">Result 8</div>
      <div class="details">Details for result 8</div>
    </div>
    <div id="result9" class="result">
      <div class="main">Result 9</div>
      <div class="details">Details for result 9</div>
    </div>
    <div id="result10" class="result">
      <div class="main">Result 10</div>
      <div class="details">Details for result 10</div>
    </div>
  </div>
</div>

A complete working example on CodePen,如果你愿意的话。