先提前预告一下:
如果需要的是单个确定高度的容器组里进行无限滚动刷新,则使用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
})
}
},
我遇到的几个问题的解决思路,可以试试
v-infinite-scroll="loadLikeMessages()" ×
改成
v-infinite-scroll="loadLikeMessages" √
然后就成功了
load(){
if(!this.noMore) {
//现在在请求
this.loading = true //《====
this.$http.get("/message/"+this.offset)
.then((res) => {
xxxxxx
this.loading = false //《======
})
}
//如果在这里this.loading = false,就会死循环
},
理论基础(重要):
判断滚动条到底部,需要用到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);//销毁滚动事件
}
到此已经能实现了