[Vue] Realize infinite scroll loading

Advance notice:

  • If you need infinite scroll refresh in a single container group with a certain height, it is most convenient to use InfiniteScroll

  • And if infinite scrolling depends on the scroll wheel of the entire window to the bottom, then use the second method. ElemntUI's InfiniteScroll cannot be implemented

Method 1: InfiniteScroll of ElemntUI

Component | Element

Pure imitation of the official website is enough, and it must be noted that v-infinite-scroll can only be set in an independent container, not the entire page window, as shown in the figure:

It cannot be implemented for the entire page window. [So the height of this container must be set, if there is no height, the default is to load the response crazily from the beginning]
insert image description here
Try the successful code display:

<el-card 
        class="message-card"
        v-infinite-scroll="load"
        :infinite-scroll-disabled="this.loading || this.noMore"
        infinite-scroll-immediate='false'
        >
        <div v-for="(item, i) in this.messages">
//用到三个变量,offset是跳过第几个
//loading和noMore都是用于什么时候禁用无限滚动加载调用方法
offset: 0,
loading: false,
noMore: false,
messages: []
load(){
    
    
	//如果是第一次加载,交给mounted而不是交给scroll的加载
	//或者loading = true表示当前正在加载,不要再触发方法,滚动条此时还在底部
    if(this.loading || this.offset==0) {
    
    return}
    //如果还有数据就请求
    if(!this.noMore) {
    
    
    	//现在在请求
        this.loading = true
        this.$http.get("/message/"+this.offset)
        .then((res) => {
    
    
        	//把数据拼上去
           this.messages = this.messages.concat(res.data.messages)
           //如果这次请求的数据不够10条,说明后面没有数据了
           if(res.data.messages.length < 10) {
    
    
               this.noMore = true;
           }
           //下一次从offset+1开始
           this.offset += 10
           //表示加载结束,此时页面也渲染好了,滚动条也不在底部,可以放开等待下一次滚动条到底部
           this.loading = false
       })
   }
},

The solutions to several problems I encountered, you can try

  • One is to automatically load all at once, change load() to load
v-infinite-scroll="loadLikeMessages()" ×
改成
v-infinite-scroll="loadLikeMessages" √
然后就成功了
  • There is also an exception You may have an infinite update loop in a component render function.
    The solution is to put this.loading = false in then after the end of the request, because it is an asynchronous request, if it will be executed in advance outside, then it will continue Trigger this.loading = true and then = false, infinite loop
load(){
    
    
    if(!this.noMore) {
    
    
    	//现在在请求
        this.loading = true  //《====
        this.$http.get("/message/"+this.offset)
        .then((res) => {
    
    
        	xxxxxx
           this.loading = false //《======
       })
   }
   
   //如果在这里this.loading = false,就会死循环
},

Method 2: Directly operate the wheel event of the window window

Theoretical basis (important):

To determine the bottom of the scroll bar, you need to use three attribute values ​​of DOM, namely scrollTop, clientHeight, and scrollHeight.

  • scrollTop : The scrolling distance of the scroll bar on the Y axis.

  • clientHeight : The height of the content viewable area.

  • scrollHeight : The height of the visible area of ​​the content plus the overflow (scroll) distance.

From the introduction of these three properties, it can be seen that the condition for scrolling to the bottom is scrollTop + clientHeight == scrollHeight.

for example:

Please add a picture description
Please add a picture description

The following three methods are first provided to obtain the information of scrollTop, clientHeight, and scrollHeight. Can be directly copied and used, written in methods

The basic principle is to compare document.body.clientHeight and document.documentElement.clientHeight

documentElement corresponds to html tags, so document.documentElement objects are most commonly used to obtain this information

//获取当前可视范围的高度
getClientHeight() {
    
    
    var clientHeight = 0;
    if (document.body.clientHeight && document.documentElement.clientHeight) {
    
    
        clientHeight = Math.min(document.body.clientHeight, document.documentElement.clientHeight)
    } else {
    
    
        clientHeight = Math.max(document.body.clientHeight, document.documentElement.clientHeight)
    }
    return clientHeight
},
    
//获取文档完整的高度
getScrollHeight() {
    
    
    return Math.max(document.body.scrollHeight, document.documentElement.scrollHeight)
}

//获取当前滚动条的位置
getScrollTop() {
    
    
    var scrollTop = 0;
    //window.pageYOffset = document.documentElement.scrollTop
    if (document.documentElement && document.documentElement.scrollTop) {
    
    
        scrollTop = document.documentElement.scrollTop
    } else if (document.body) {
    
    
        scrollTop = document.body.scrollTop
    }
    return scrollTop
}

Then we need a listener to listen to the scrolling event, which is defined in the mounted hook function, because we install it directly to the window, not to a certain component or label. Therefore, there is no need to add a response event, but the callback function to monitor must be specified, and the most important thing is to pass in a true parameter at the end, otherwise it will fail. But it should be noted that the listener of the scroll event needs to be destroyed manually, otherwise an exception will be exposed.

methods: {
    
     
    //使用上面介绍的方法
    getScrollTop(){
    
    },
    getClientHeight(){
    
    },
    getScrollHeight(){
    
    },
    //回调函数
    windowScroll() {
    
    
        //获取三个值
        var scrollTop = this.getScrollTop()
        var clientHeight = this.getClientHeight()
        var scrollHeight = this.getScrollHeight()
        //如果满足公式则,确实到底了
        if(scrollTop+clientHeight == scrollHeight){
    
    
            //发送异步请求请求数据,同时携带offset并自增offset
            //noMore是自定义变量,如果是最后一批数据则以后都不加载
            if(!this.noMore) {
    
    
                this.$http.get("/xxxx"+this.offset).then((res) => {
    
    
                    this.news = this.news.concat(res.data.news)
                    if(res.data.news.length < 10) {
    
    
                        this.noMore = true;
                    }
                    //记得对offset进行自增
                    this.offset += 10
                })
            }
        }
    }
}
mounted() {
    
    
    window.addEventListener('scroll', this.windowScroll,true) //监听页面滚动
},
destroyed() {
    
    
    window.removeEventListener("scroll", this.windowScroll);//销毁滚动事件
}
//删除滚动监听器,建议使用beforeRouteLeave,因为destroyed()钩子在路由跳转时不会触发
beforeRouteLeave() {
    
    
	window.removeEventListener("scroll", this.windowScroll);//销毁滚动事件
}

So far it has been achieved

Guess you like

Origin blog.csdn.net/NineWaited/article/details/126387768