virtual-scroller(上)
<html> <head> <meta charset="UTF-8"> <title>test</title> <style type="text/css"> .viewpoint { margin: 20px auto; width: 380px; height: 200px; border: 1px solid #333; overflow-y:scroll; } .canvas { height: 20000px; } </style> </head> <body> <div class="viewpoint"> <div class="canvas"></div> </div> <div class="log"></div> <script> var lineHeight = 10; var data = new Array(2000).fill(0).map((d, i) => ({ v: i })); var buffer = { start: 0, limit: 200/ 10, domain:[0, 20], isAmong(value) { return buffer.domain[0] <= value && value <= buffer.domain[1]; }, preLoad(dir, index) { if (dir === 0) return false; var current = ~~(index/ lineHeight), [start, end] = buffer.domain; // scroll up if (dir < 0 && current < Math.max(0, start + buffer.limit)) { end = buffer.isAmong(current) ? start - 1 : current; start = end - buffer.limit; buffer.domain = [start, end]; return true; } // scroll down if (dir > 0 && current > end - buffer.limit) { start = buffer.isAmong(current) ? end + 1 : current; end = start + buffer.limit; buffer.domain = [start, end]; return true; } return false; } }; var scroller = { dir: 0, // -1,0,-1 preIndex: 0, on(fn) { this.fn = function(index) { log('current', index); scroller.dir = index - scroller.preIndex; if (buffer.preLoad(scroller.dir, scroller.preIndex = index)) { fn(scroller.dir > 0 ? 1 : -1, buffer.domain, index); } }; }, fire() {this.fn.apply(this, arguments);} }; var dataView = { getRange(start, end) { return data.slice(start, end); } }; document.querySelector('.viewpoint').addEventListener('scroll', function(evt) { // console.log(this.scrollTop); scroller.fire(this.scrollTop); }); scroller.on(function(dir, [start, limit], offsetTop) { console.log(dir, start, limit, offsetTop); // console.log(dataView.getRange(start, limit)); }); var $log = document.querySelector('.log'); function log(...args) { $log.innerHTML = args; } </script> </body> </html>