virtual-scroller(下)

<html>
<head>
    <meta charset="UTF-8">
    <title>test</title>

    <style type="text/css">
        .viewpoint {
            margin: 20px auto;
            width: 380px;
            height: 301px;
            border: 1px solid #333;
            overflow-y:auto;
        }
        .canvas {
            position: relative;
            height: auto;
        }
        .row {
            position: absolute;
            height: 10px;
            line-height: 10px;
        }
    </style>
    <script src="jquery.js"></script>
</head>
<body>
    <div class="viewpoint">
        <div class="canvas"></div>
    </div>
    <div class="log"></div>
    <script>
        var lineHeight = 10;
        var viewpointHeight = $('.viewpoint').height();
        var data = new Array(909).fill(0).map((d, i) => ({ v: i }));
        var limit = Math.min(Math.ceil(viewpointHeight/ lineHeight) - 1, data.length - 1);

        $('.canvas').height(lineHeight * data.length);

        var buffer = {
            start: 0,
            end: limit,
            limit: limit,
            total: data.length,
            domain:[0, limit],
            isAmong(index) {
                return buffer.start <= index && index <= buffer.end;
            },
            preLoad(dir, current) {
                if (dir === 0) return false;

                var start = buffer.start;
                var end = buffer.end;
                var cacheTwice = 3;

                // scroll up
                if (dir < 0 && start === 0) return false;
                if (dir < 0 && current < Math.max(0, start + buffer.limit)) {
                    if (buffer.isAmong(current)) {
                        end = start - 1;
                        start = Math.max(0, end - buffer.limit);
                    } else {
                        end = current + buffer.limit;
                        start = Math.max(0, current - 2 * buffer.limit);
                        // cacheTwice = 2;
                    }

                    buffer.domain = [start, end];
                    buffer.start = start;
                    buffer.end = Math.min(start + cacheTwice * buffer.limit, buffer.end);
                    return true;
                } 

                // scroll down
                if (dir > 0 && end === buffer.total) return false;
                if (dir > 0 && current > end - buffer.limit) {
                    if (buffer.isAmong(current)) {
                        start = end + 1;
                        end = Math.min(buffer.total, start + buffer.limit); 
                    } else {
                        start = current - buffer.limit;
                        end = Math.min(buffer.total, current + 2 * buffer.limit);
                        // cacheTwice = 2;
                    }

                    buffer.domain = [start, end];
                    buffer.end = end;
                    buffer.start = Math.max(buffer.start, end - cacheTwice * buffer.limit);
                    return true;
                }
                
                return false;
            }
        };
        var scroller = { 
            dir: 0, // -1,0,-1
            preIndex: 0,
            index: 0,
            on(fn) {
                this.fn = function(offsetTop) {
                    log('current', offsetTop);
                    scroller.dir = offsetTop - scroller.preIndex;
                    scroller.index = ~~((scroller.preIndex = offsetTop)/ lineHeight);
                    if (buffer.preLoad(scroller.dir, scroller.index)) {
                        fn(
                            scroller.dir > 0 ? 1 : -1, 
                            buffer.domain, 
                            buffer.start, 
                            buffer.end, 
                            scroller.index,
                            buffer.total
                        );
                    }
                };
            }, 
            fire() {this.fn.apply(this, arguments);} 
        };

        var dataView = {
            nodeList: [],
            init() {
                var domain = buffer.domain;
                dataView.render(1, domain);
            },
            fullNodes() {
                return dataView.nodeList.length >= 3 * limit;
            },
            getNodes(dir, first, last) {
                if (dataView.fullNodes()) {
                    let selected;

                    if (dir > 0) {
                        selected = dataView.nodeList.slice(0, last - first + 1);
                        dataView.nodeList = dataView.nodeList.slice(last - first + 1).concat(selected);
                        
                    } else {
                        selected = dataView.nodeList.slice(first - last - 1);
                        dataView.nodeList = selected.concat(dataView.nodeList.slice(0, first - last - 1));
                    }
                    
                    return selected;
                }
                
                var nodes = [];
                for (let i = first; i <= last; i++) {
                     nodes.push(function() {
                          var $node = $('<div/>').addClass('row');

                          return {
                              src: $node,
                              set(row, top) {
                                  return $node.css('top', top * lineHeight).text(row.v);
                             }
                          };
                     }());
                }

                if (dir > 0) {
                    dataView.nodeList = dataView.nodeList.concat(nodes);
                } else {
                    dataView.nodeList = nodes.concat(dataView.nodeList);
                }

                return nodes;
            },
            render(dir, [first, last]) {
                var nodes = dataView.getNodes(dir, first, last);
                console.log(nodes.length);

                if (dataView.isFullNodes) {
                    data.slice(first, last + 1).forEach((row, i) => {
                        nodes[i].set(row, first + i);
                    });

                    return;
                }
                var parent = $('<div/>');

                data.slice(first, last + 1).forEach((row, i) => {
                    parent.append(nodes[i].set(row, first + i));
                });

                $('.canvas').append(parent.children());

                if (dataView.fullNodes()) {
                    dataView.isFullNodes = true;
                }        
            }
        };
        

        document.querySelector('.viewpoint').addEventListener('scroll', function(evt) {
            // console.log(this.scrollTop);
            scroller.fire(this.scrollTop);
        });

        scroller.on(function(dir, domain, start, end, offsetTop, total) {
            console.log(`${dir}, add:[${domain}] [${start}-${end}], ${offsetTop}, nodes:${dataView.nodeList.length}`);
            dataView.render(dir, domain);
        });

        dataView.init();


        var $log = document.querySelector('.log');
        function log(...args) {
            $log.innerHTML = args;
        }
    </script>
</body>
</html>

 

 1 var lockColumnManager = {
 2             data: [],
 3             totalOffset: 0,
 4             add(col) {
 5                 this.data.unshift(col);
 6                 this.reCalc();
 7             },
 8             remove(delCol) {
 9                 this.data = this.data.filter(col => col !== delCol);
10                 this.reCalc();
11             },
12             reCalc(){
13                 this.totalOffset = this.data.reduce((offset, col) => {
14                     offset += col.w;
15                     col.offsetLeft = offset;
16                     return offset;
17                 }, 0);
18             }
19         };

 

posted @ 2017-08-01 22:25  风之约  阅读(314)  评论(0编辑  收藏  举报