blob: bb470f2e3142079fbdd2b77c99c087c71dde03d2 [file] [log] [blame]
<!doctype html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<style>
html, body {
height: 100%;
overflow: hidden;
}
* {
box-sizing: border-box;
}
.scrollable {
position: relative;
height: 100%;
overflow-y: scroll;
overflow-x: hidden;
}
.stretcher {
position: absolute;
visibility: hidden;
left: 0;
top: 0;
width: 1px;
height: 1000000px;
}
.item {
background-color: #FFF;
width: 100%;
position: absolute;
left: 0;
top: 0;
-webkit-transform: translate3d(0, 0, 0);
height: 50px;
border: 1px solid #000;
padding: 10px;
}
body {
-ms-touch-action: none;
display: none;
}
@keyframes slideIn {
from {
transform: translate3d(100%, 0, 0);
}
to {
transform: translate3d(0, 0, 0);
}
}
@keyframes slideOut {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(-100%, 0, 0);
}
}
@-webkit-keyframes slideIn {
from {
-webkit-transform: translate3d(100%, 0, 0);
}
to {
-webkit-transform: translate3d(0, 0, 0);
}
}
@-webkit-keyframes slideOut {
from {
-webkit-transform: translate3d(0, 0, 0);
}
to {
-webkit-transform: translate3d(-100%, 0, 0);
}
}
.list {
transform: translate3d(100%, 0, 0);
-webkit-transform: translate3d(100%, 0, 0);
border: 5px solid red;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
</style>
<script>
var LIST_COUNT = 10;
for (var i = 0; i < LIST_COUNT; i++) {
document.write('<div class="list scrollable" style="border-color: #' +
Math.floor(Math.random() * 16777215).toString(16) + '"><div class="stretcher"></div></div>');
}
var transform = 'webkitTransform' in document.body.style ? 'webkitTransform' : 'transform';
function InfiniteList(options) {
var scrollable = options.element,
itemTemplate = options.template,
renderFn = options.render,
itemHeight = options.itemHeight || 50,
itemsPool = [],
itemsPoolCount = 0,
topItemIndex = 0,
scrollableHeight = window.innerHeight,
div, i;
function update() {
var newScrollTop = scrollable.scrollTop,
newTopItemIndex = Math.floor(newScrollTop / itemHeight),
delta = newTopItemIndex - topItemIndex;
if (delta !== 0) {
if (Math.abs(delta) > itemsPoolCount) {
renderAllItems(newTopItemIndex);
}
else {
renderItems(delta);
}
}
}
function renderAllItems(index) {
for (i = 0; i < itemsPoolCount; i++) {
renderItem(itemsPool[i], index + i);
}
topItemIndex = index;
}
function renderItems(count) {
var lastIndex = itemsPoolCount - 1;
// Recycle top items to render at the bottom
if (count > 0) {
for (i = 0; i < count; i++) {
div = itemsPool[i];
renderItem(div, topItemIndex + itemsPoolCount + i);
}
itemsPool.push.apply(itemsPool, itemsPool.splice(0, count));
topItemIndex += count;
}
// Recycle bottom items to render at the top
else {
count = Math.abs(count);
for (i = lastIndex; i > lastIndex - count; i--) {
div = itemsPool[i];
renderItem(div, --topItemIndex);
}
itemsPool.unshift.apply(itemsPool, itemsPool.splice(lastIndex - count + 1, count));
}
}
function renderItem(div, index) {
renderFn(div, index);
div.style[transform] = 'translate3d(0, ' + (index * itemHeight) + 'px' + ', 0)';
}
function loop() {
window.requestAnimationFrame(function() {
update();
loop();
});
}
window.addEventListener('DOMContentLoaded', function() {
console.log('DOMContentLoaded');
var holder = document.createElement('div'),
itemsHtml = [];
itemsPoolCount = Math.ceil(scrollableHeight / itemHeight) + 1;
for (i = 0; i < itemsPoolCount; i++) {
itemsHtml.push(itemTemplate);
}
holder.innerHTML = itemsHtml.join('');
itemsPool.push.apply(itemsPool, holder.children);
itemsPool.forEach(function(item) {
item.style.height = itemHeight + 'px';
scrollable.appendChild(item);
});
renderAllItems(0);
loop();
});
}
document.body.style.display = 'block';
var lists = document.querySelectorAll('.list'),
prefix = 'onwebkitanimationend' in window ? '-webkit-' : '',
count = 0,
index = 0;
[].forEach.call(lists, function(list) {
new InfiniteList({
element: list,
template: '<div class="item"></div>',
render: function(div, index) {
div.textContent = 'This is item #' + index;
}
});
});
function animate(index, name) {
var list = lists[index];
list.style.setProperty(prefix + 'animation-name', name, null);
list.style.setProperty(prefix + 'animation-duration', '5s', null);
list.style.setProperty(prefix + 'animation-timing-function', 'ease-out', null);
list.style.setProperty(prefix + 'animation-fill-mode', 'forwards', null);
count++;
}
function next() {
if (index > lists.length - 1) {
index = 0;
}
animate(index, 'slideOut');
if (++index > lists.length - 1) {
index = 0;
}
animate(index, 'slideIn');
}
document.addEventListener(prefix ? 'webkitAnimationEnd' : 'animationend', function() {
console.log('animationend');
if (--count === 0) {
next();
}
}, true);
next();
</script>