| <!doctype html> |
| <!-- |
| Copyright (c) 2018 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| <html> |
| <head> |
| <title>infinite-scroll</title> |
| <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes"> |
| <style> |
| html { |
| height: 100%; |
| } |
| body { |
| display: block; |
| height: 100%; |
| margin: 0; |
| } |
| #container { |
| overflow-y: scroll; |
| height: 100%; |
| margin: 0; |
| contain: layout; |
| } |
| #runway { |
| height: 100000px; |
| contain: layout; |
| } |
| .item { |
| -webkit-transform: translate3d(0,0,0); |
| box-sizing: border-box; |
| overflow: hidden; |
| contain: layout; |
| } |
| |
| .conversation { |
| font-family: sans-serif; |
| height: 70px; |
| display: flex; |
| border-bottom: 1px solid lightgray; |
| } |
| .avatar { |
| display: flex; |
| flex-shrink: 0; |
| color: white; |
| align-items: center; |
| justify-content: center; |
| font-size: 40px; |
| width: 50px; |
| height: 50px; |
| margin: 10px; |
| background-color: lightblue; |
| } |
| .summary { |
| flex: 1; |
| flex-shrink: 0; |
| display: flex; |
| flex-direction: column; |
| padding: 10px 10px 10px 0px; |
| } |
| .topline { |
| display: flex; |
| flex-shrink: 0; |
| } |
| .participants { |
| flex: 1; |
| flex-shrink: 0; |
| font-weight: bold; |
| } |
| .time { |
| flex-shrink: 0; |
| font-size: 12px; |
| color: #444; |
| } |
| .bottomline { |
| flex-shrink: 0; |
| display: flex; |
| } |
| .preview { |
| flex: 1; |
| flex-shrink: 0; |
| font-size: 12px; |
| height: 2em; |
| text-overflow: ellipsis; |
| } |
| .subject { |
| font-weight: bold; |
| } |
| .snippet { |
| color: #444; |
| } |
| .trinkets { |
| flex-shrink: 0; |
| font-size: 20px; |
| } |
| .fixed { |
| position: fixed; |
| top: 0; |
| left: 50%; |
| transform: translate(-50%, 0); |
| border: 3px solid #73AD21; |
| } |
| </style> |
| </head> |
| <body > |
| <div id="runway"> |
| <template> |
| <div class="item conversation"> |
| <div class="avatar">A</div> |
| <div class="summary"> |
| <div class="topline"> |
| <div class="participants">{{ participants }}</div> |
| <div class="time">{{ time }}</div> |
| </div> |
| <div class="bottomline"> |
| <div class="preview"><span class="subject">{{ subject }}</span> — |
| <span class="snippet">{{ snippet }}</span></div> |
| <div class="trinkets">☆</div> |
| </div> |
| </div> |
| </div> |
| </template> |
| </div> |
| <div class="fixed">This div element has position: fixed</div> |
| <script> |
| var qs = (function(a) { |
| if (a == "") return {}; |
| var b = {}; |
| for (var i = 0; i < a.length; ++i) |
| { |
| var p=a[i].split('=', 2); |
| if (p.length == 1) |
| b[p[0]] = ""; |
| else |
| b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " ")); |
| } |
| return b; |
| })(window.location.search.substr(1).split('&')); |
| |
| function getRandomItem(array) { |
| return array[Math.floor(Math.random() * array.length)]; |
| } |
| function generateFakeData() { |
| var kNumberOfItems = 500; |
| var possibleParticipants = [ |
| 'Adam', 'Ojan', 'Elliot', 'Chris', |
| ]; |
| var possibleTimes = [ |
| 'Now', 'Yesterday', 'Last week', |
| ]; |
| var possibleSubjects = [ |
| 'Do you even bench?', |
| 'I like to scroll forever', |
| 'Lunch', |
| 'What if my subject is really long? Longer than that. Like really, really, long?', |
| ]; |
| var possibleSnippets = [ |
| 'Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.', |
| 'When, in disgrace with fortune and men\'s eyes, I all alone beweep my outcast state,', |
| 'We the People of the United States, in Order to form a more perfect Union, establish Justice, insure domestic Tranquility', |
| ]; |
| var data = new Array(kNumberOfItems); |
| for (var i = 0; i < kNumberOfItems; ++i) { |
| data[i] = { |
| participants: getRandomItem(possibleParticipants), |
| time: getRandomItem(possibleTimes), |
| subject: getRandomItem(possibleSubjects), |
| snippet: getRandomItem(possibleSnippets), |
| } |
| console.log(data[i]); |
| } |
| return data; |
| } |
| |
| var data = generateFakeData(); |
| |
| "use strict"; |
| (function(exports) { |
| var kHeight = 70; |
| var kPhysicalCount = qs['layer_count']; |
| |
| var container = window; |
| var runway = document.getElementById('runway'); |
| |
| |
| var template = runway.querySelector('template'); |
| var items = new Array(kPhysicalCount); |
| for (var i = 0; i < kPhysicalCount; ++i) { |
| var fragment = template.content.cloneNode(true); |
| runway.appendChild(fragment); |
| var item = runway.lastElementChild; |
| items[i] = item; |
| item.transformValue_ = 0; |
| item.participants_ = item.querySelector('.participants').firstChild; |
| item.time_ = item.querySelector('.time').firstChild; |
| item.subject_ = item.querySelector('.subject').firstChild; |
| item.snippet_ = item.querySelector('.snippet').firstChild; |
| |
| updateText(item, i); |
| } |
| |
| var physicalHeight = kHeight * kPhysicalCount; |
| |
| function updateText(item, index) { |
| var datum = data[index % data.length]; |
| item.participants_.nodeValue = datum.participants; |
| item.time_.nodeValue = datum.time; |
| item.subject_.nodeValue = datum.subject; |
| item.snippet_.nodeValue = datum.snippet; |
| } |
| |
| container.addEventListener('scroll', function(e) { |
| var scrollTop = container.scrollY; |
| |
| var firstVirtualIndex = Math.floor(scrollTop / kHeight); |
| var firstPhysicalIndex = firstVirtualIndex % kPhysicalCount; |
| |
| var baseVirtualIndex = firstVirtualIndex - firstPhysicalIndex; |
| |
| var baseTransformValue = kHeight * baseVirtualIndex; |
| var nextTransformValue = baseTransformValue + physicalHeight; |
| |
| var baseTransformString = 'translate3d(0,' + baseTransformValue + 'px,0)'; |
| var nextTransformString = 'translate3d(0,' + nextTransformValue + 'px,0)'; |
| |
| window.requestAnimationFrame(function() { |
| for (var i = 0; i < firstPhysicalIndex; ++i) { |
| var item = items[i]; |
| if (item.transformValue_ != nextTransformValue) { |
| // NOTE(vmiura): Removed updateText to remove layout changes from the benchmark. |
| //updateText(item, baseVirtualIndex + kPhysicalCount + i); |
| item.style.WebkitTransform = nextTransformString; |
| item.transformValue_ = nextTransformValue; |
| } |
| |
| } |
| for (var i = firstPhysicalIndex; i < kPhysicalCount; ++i) { |
| var item = items[i]; |
| if (item.transformValue_ != baseTransformValue) { |
| // NOTE(vmiura): Removed updateText to remove layout changes from the benchmark. |
| //updateText(item, baseVirtualIndex + i); |
| item.style.WebkitTransform = baseTransformString; |
| item.transformValue_ = baseTransformValue; |
| } |
| } |
| }); |
| }); |
| })(window); |
| </script> |
| </body> |
| </html> |