scroll

321 阅读1分钟
    new Vue({
        el: "#scroll-area",
        data: {
            msg: "滚动",
            list: [] ,
            reachBottomDistance: 100,
            isReachBottom: false,
            scrollHeight: 0,
            offsetHeight: 0
        },
        beforeMount() {
            this.addNumber();
        },
        mounted() {
            const target = document.getElementById("scroll-area");
            this.scrollHeight = target.scrollHeight;
            this.offsetHeight = Math.ceil(target.getBoundingClientRect().height);
        },
        methods: {
            onScroll(e) {
                const target = e.target;
                const scrollTop = target.scrollTop;
                if(offsetHeight + scrollTop < this.scrollHeight && this.isReachBottom) {
                    this.isReachBottom = false;
                }
                if(this.isReachBottom) {
                    return;
                }
                if(offsetHeight + scrollTop + this.reachBottomDistance >= this.scrollHeight) {
                    this.isReachBottom = true;
                    console.log("botton");
                }
            },
            addNumber() {
                var added = [];
                for(var i = 0; i < 50; i ++) {
                    added.push(Math.random());
                }
                this.list = this.list.concat(added);
            }
        }
    })
    
    
    
    
    
    
    
    //fix item height
            new Vue({
        el: ".list-view",
        data: {
            start: 0,
            end: null,
            visibleData: [],
            visibleCount: null,
            itemHeight: 30
        },
        computed: {
            contentHeight() {
                return  this.allData.length * this.itemHeight + 'px' ;
            }
        },
        beforeCreate() {
            let i = 0;
            this.allData = [];
            while(i < 10000) {
                this.allData.push({
                    value: Math.random()
                });
                i++;
            }
        },
        mounted() {
            this.visibleCount = Math.ceil(this.$el.clientHeight / this.itemHeight);
            this.updateVisibleData();
        },
        methods: {
            onScroll(e) {
                const scrollTop = this.$el.scrollTop;
                this.updateVisibleData(scrollTop);
            },
            updateVisibleData(scrollTop = 0) {
                this.start = Math.floor(scrollTop / this.itemHeight);
                this.end = this.start + this.visibleCount;
                this.visibleData = this.allData.slice(this.start, this.end);
                // 把可见区域的 top 设置为起始元素在整个列表中的位置(使用 transform 是为了更好的性能)
                this.$refs.content.style.webkitTransform = `translate3d(0, ${this.start * this.itemHeight}px, 0)`;
            }
        }
    })
    
    
    
    
    
    //flex item height
            new Vue({
        el: ".list-view",
        data: {
            start: 0,
            end: null,
            visibleData: []
        },
        computed: {
            contentHeight() {
                let total = 0;
                this.allData.forEach((item, index) => {
                    total += this.itemSizeGetter(item, index);
                })
                return  total + 'px' ;
            }
        },
        beforeCreate() {
            let i = 0;
            this.allData = [];
            while(i < 10000) {
                this.allData.push({
                    value: Math.random()
                });
                i++;
            }

            this.itemSizeGetter = function(item, index) {
                //TODO
            };
        },
        mounted() {
            this.updateVisibleData();
        },
        methods: {
            onScroll(e) {
                const scrollTop = this.$el.scrollTop;
                this.updateVisibleData(scrollTop);
            },
            updateVisibleData(scrollTop = 0) {
                this.start = this.findNearestItemIndex(scrollTop);
                this.end = this.findNearestItemIndex(scrollTop + this.$el.clientHeight);
                this.visibleData = this.allData.slice(this.start, this.end + 1);
                // 把可见区域的 top 设置为起始元素在整个列表中的位置(使用 transform 是为了更好的性能)
                this.$refs.content.style.webkitTransform = `translate3d(0, ${this.getItemOffset(start)}px, 0)`;
            },
            findNearestItemIndex(scrollTop) {
                let top = 0;
                for(let i=0, j = this.allData.length; i<j; i++) {
                    const size = this.itemSizeGetter(this.allData[i], i);
                    total += size;
                    if(total > scrollTop || i === j-1) {
                        return i;
                    }
                }
                return 0;
            },
            getItemOffset(index) {
                for(let i=0, j = Math.min(index, this.allData.length -1); i <= j; i++ ) {
                    const size = this.itemSizeGetter(this.allData[i], i);
                    if(i === j) {
                        return total;
                    }
                    total += size;
                }
                return 0;
            }
        }
    })
    
    
    
           // https://juejin.cn/post/6844903577631227912
    new Vue({
        el: ".list-view",
        data: {
            start: 0,
            lastMeasuredIndex: -1,
            visibleData: [],
            sizeAndOffsetCache: {},
            estimatedItemSize: 30
        },
        computed: {
            contentHeight() {
                let total = 0;
                if(this.lastMeasuredIndex >= 0) {
                    const lastMeasured = this.getLastMeasuredSizeAndOffset();
                    total = lastMeasured.offset + lastMeasured.size + (this.allData.length -1 - this.lastMeasuredIndex) * this.estimatedItemSize;
                }else {
                    total = this.allData.length * this.estimatedItemSize;
                }
                return  total + 'px' ;
            }
        },
        beforeCreate() {
            let i = 0;
            this.allData = [];
            while(i < 10000) {
                this.allData.push({
                    value: Math.random()
                });
                i++;
            }

            this.itemSizeGetter = function(item, index) {
                //TODO
                if(index % 2 === 0) {
                    return 20;
                }
                return 30;
            };
        },
        mounted() {
            this.updateVisibleData();
        },
        methods: {
            onScroll(e) {
                const scrollTop = this.$el.scrollTop;
                this.updateVisibleData(scrollTop);
            },
            updateVisibleData(scrollTop = 0) {
                this.start = this.findNearestItemIndex(scrollTop);
                this.end = this.findNearestItemIndex(scrollTop + this.$el.clientHeight);
                this.visibleData = this.allData.slice(this.start, this.end + 1);
                // 把可见区域的 top 设置为起始元素在整个列表中的位置(使用 transform 是为了更好的性能)
                this.$refs.content.style.webkitTransform = `translate3d(0, ${this.getItemSizeAndOffset(this.start).offset}px, 0)`;
            },
            findNearestItemIndex(scrollTop) {
                let top = 0;
                for(let i=0, j = this.allData.length; i<j; i++) {
                    const size = this.getItemSizeAndOffset(i).size;
                    top += size;
                    if(top > scrollTop || i === j-1) {
                        return i;
                    }
                }
                return 0;
            },
            getItemSizeAndOffset(index) {
                if(this.lastMeasuredIndex >= index) {
                    return this.sizeAndOffsetCache[index];
                }
                const lastMeasured = this.getLastMeasuredSizeAndOffset();
                let offset = lastMeasured.offset + lastMeasured.size;  
                for(let i= this.lastMeasuredIndex + 1; i <= index; i++ ) {
                    const size = this.itemSizeGetter(this.allData[i], i);
                    this.sizeAndOffsetCache[i] = {
                        size: size,
                        offset: offset
                    };
                    offset += size;
                }
                if(index > this.lastMeasuredIndex) {
                    this.lastMeasuredIndex = index;
                }

                return this.sizeAndOffsetCache[index];
            },
            getLastMeasuredSizeAndOffset() {
                return this.lastMeasuredIndex >= 0 ? this.sizeAndOffsetCache[this.lastMeasuredIndex] : {
                    offset: 0,
                    size: 0
                };
            }
        }
    })