【Vue】实现无限滚动加载

先提前预告一下:

  • 如果需要的是单个确定高度的容器组里进行无限滚动刷新,则使用InfiniteScroll最方便

  • 而如果无限滚动依赖的是整个窗口的滚轮到底部,则使用法二才行。ElemntUI的InfiniteScroll无法实现

法一:ElemntUI的InfiniteScroll

组件 | Element

纯模仿官网即可,一定要注意v-infinite-scroll只能是设置在某个独立容器中,而不能是整个页面窗口,如图:

无法对整个页面窗口实现。【所以这个容器必须设置高度,如果没有高度,则默认是一开始就直接疯狂加载响应】
在这里插入图片描述
尝试成功的代码展示:

<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
       })
   }
},

我遇到的几个问题的解决思路,可以试试

  • 一个是自动一次性全加载了,把load()改成load
v-infinite-scroll="loadLikeMessages()" ×
改成
v-infinite-scroll="loadLikeMessages" √
然后就成功了
  • 还有一个是异常You may have an infinite update loop in a component render function.
    解决是把this.loading = false放在请求结束后的then里,因为是异步请求,如果在外面会提前执行,那么就是不断触发this.loading = true后又 = false,死循环
load(){
    
    
    if(!this.noMore) {
    
    
    	//现在在请求
        this.loading = true  //《====
        this.$http.get("/message/"+this.offset)
        .then((res) => {
    
    
        	xxxxxx
           this.loading = false //《======
       })
   }
   
   //如果在这里this.loading = false,就会死循环
},

法二:直接操作window窗口的滚轮事件

理论基础(重要):

判断滚动条到底部,需要用到DOM的三个属性值,即scrollTop、clientHeight、scrollHeight。

  • scrollTop : 滚动条在Y轴上的滚动距离。

  • clientHeight : 内容可视区域的高度。

  • scrollHeight : 内容可视区域的高度加上溢出(滚动)的距离。

从这个三个属性的介绍就可以看出来,滚动条到底部的条件即为scrollTop + clientHeight == scrollHeight。

举例说明:

请添加图片描述
请添加图片描述

下面先提供三个方法,用来获取scrollTop、clientHeight、scrollHeight的信息。可直接复制使用的,写在methods里

基本原理都是比较document.body.clientHeight与document.documentElement.clientHeight

documentElement 对应的是 html 标签,因此最常用document.documentElement对象来获取这些信息

//获取当前可视范围的高度
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
}

然后我们需要一个监听器,监听滚动事件,在mounted钩子函数中就进行定义,因为我们是直接给window加装的,而不是给某个组件或者标签。因此不需要加入响应事件,但是要指定监听的回调函数,并且最重要的是最后要传入一个true的参数,否则失效。但是要注意,滚动事件的监听器需要手动销毁,否则会曝出异常。

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);//销毁滚动事件
}

到此已经能实现了

猜你喜欢

转载自blog.csdn.net/NineWaited/article/details/126387768