);
如上所示: 我们使用 window.innerHeight 得到浏览器的高度, 使用 scrollTop 得到滚动被卷起来的高度, 使用 scrollHeight 得到页面的总高度。
如果 windowHeight + scrollTop + 50 大于 scrollHeight 时, 说明到底部了,这里 + 50 是因为这样不会一直到最底下才开始,而是快到的时候就开始,用户体验会好一些。
接下来就是如何监测高度的变化
即我们怎么知道到达底部呢?
有两种方法
方法一:使用setInterval定时器来每个一段时间(比如500ms)就循环一次,获取到各种高度,判断是否达到最底部,然后进行相应的懒加载代码, 优点:对浏览器的支持都比较好,所以用起来不会有太大问题。 缺点1:无论我们是否在滑动,定时器在不断的执行,虽然对性能的影响不是很大,但是很明显,这不是他该发挥的地方。缺点二、setInterval只是对某一段函数的重复执行,但是对于我目前的项目而言(即不同种类下的商品都会滚动)显然是需要写多次的。
方法二: 使用onscroll事件, jqury是支持的,但是zepto不支持,所以说我们直接用原生的更好, window.addEventListener("scroll", function () {}, false);即可。 优点1:语义明确,充分发挥了各自的作用。 比较灵敏。 优点2:因为window.addEventListener() 是将scroll事件绑定到了window上,所以这时全局的,在哪里都可以使用,就像RN的write once , run everywhere。 缺点: 据说,其在ios设备上的触发是在 滑动之后, 而不是滑动一开始就触发, 但对于本项目的懒加载功能是没有影响的。
在移动端,这里使用 ontouchmove 事件处理程序的效果要好一些,因为如果使用scroll,当用户已经拉到了底部的时候,这时候可能就不会触发scroll了,而 touchmove 是一定会触发的。
对,最终选用第二种方法, 如下所示:
window.addEventListener('scroll', function(e) {
let windowHeight = window.innerHeight; // 1334px
let scrollTop = $('body')[0].scrollTop; // 如果在没有滚动的情况下就是0
let scrollHeight = $('body')[0].scrollHeight; // 即总的高度。如果在不超过一整页的情况下得到的也是
console.log(windowHeight + scrollTop);
console.log(scrollHeight);
if ((windowHeight + scrollTop) + 50 >= scrollHeight) {
console.log("start ajax request");
注意: 这里加 50 还是加一个别的数字,这是一个技巧,要根据情况进行设定, 比如我们希望还没有到底就可以开始加载更多了,就可以多加一些,如果希望到底部才加载更多,就设置加10或者5甚至不加都是可以的。
第三步就是需要开始请求更多的数据了
if ((windowHeight + scrollTop) + 50 >= scrollHeight) {
console.log("start");
var contentObj = {
id: that.$store.state.items[that.$store.state.curIndex].id,
index: that.$store.state.curIndex,
offset: (that.$store.state.offsets[that.$store.state.curIndex] + 10)
that.getMoreCurContent(contentObj);
即当满足某一个条件时,我就可以向后台发送请求了,这里的函数 that.getMoreCurContentactions中的,因为异步请求我们一般都放在actions里。
但是这样存在一个问题: 显然在我向下拉的时候, 满足这个条件的情况不只一次,那么就会导致: that.getMoreCurContent被发送了很多次!
所以为了解决这个问题,我们需要立一个flag,判定是否能进行, 比如,在 state 中我们添加一个 process 数组,数组的长度就是分类的长度,每一个都是一个布尔值,我们一旦发送一个请求,就设置这个布尔值为true,设置了之后,直到请求成功,我们再设置为false,并且如果说,我们之前设定的pageSize为10, 而这次获取的数据为10的情况下才能让 process[某个分类的index]设置为false,如果不为10, 说明没有更多的数据了,那么我们同样在else语句下设置为true即可,这样,就不会再请求了。
这里有一个好处是 --- 一旦我们将 process 设置为一个数组,那么每个分类的请求之间就相互不会影响了, 而到每一个分类下,我们只需要一个 state.curIndex 来处理当前即可。 因为他们用的是不同的函数。
如下所示:
created () {
var that = this;
window.addEventListener('scroll', function(e) {
let windowHeight = window.innerHeight;
let scrollTop = $('body')[0].scrollTop;
let scrollHeight = $('body')[0].scrollHeight;
console.log(windowHeight + scrollTop);
console.log(scrollHeight);
if ((windowHeight + scrollTop) + 50 >= scrollHeight) {
console.log("start");
var contentObj = {
id: that.$store.state.items[that.$store.state.curIndex].id,
index: that.$store.state.curIndex,
offset: (that.$store.state.offsets[that.$store.state.curIndex] + 10)
// 表示正在进行中时,不再请求,
if (that.$store.state.process[that.$store.state.curIndex] == true) {
// 什么都不做,所以这里不需要这样写,只是这样可能会比较好理解一些。
} else {
that.getMoreCurContent(contentObj);
即进入之后,我们就开始监控了, 这里的offsets 也是一个数组,他的好处是可以做到互不影响。
getMoreCurContent ({commit, state}, contentObj) {
// 设置 that.$store.state.process == true
var boolObj = {
index: contentObj.index,
bool: true
commit(UPDATE_PROCESS, boolObj);
var items = state.items;
var content = {
"isSingle": 1,
"sbid": 13729792,
"catalog3": contentObj.id,
"offset": contentObj.offset,
"pageSize": 10
axios.post('/bbg/goods/get_goods_list_wechat', qs.stringify({"data": JSON.stringify(content)}))
.then(function (response) {
if (response.data.code == 626) {
if (response.data.data.length > 0) {
var a = 0;
for (let i = 0; i < response.data.data.length; i++) {
var obj = {
index: contentObj.index,
item: response.data.data[i]
commit(UPDATE_CONTENT, obj);
a++;
if (a == 10) {
alert("哈哈");
// 如果等于10,说明还有其他的,那么我们就可以把这个分类的offset增加,继续请求数组,如果说刚好没有数据了,那么就是0,后面也会给出相应的处理的。
var offsetObj = {
index: contentObj.index,
offset: contentObj.offset
commit(UPDATE_OFFSET, offsetObj);
var boolObj = {
index: contentObj.index,
bool: false
commit(UPDATE_PROCESS, boolObj);
} else {
var boolObj = {
index: contentObj.index,
bool: true
commit(UPDATE_PROCESS, boolObj);
}).catch(function (error) {
console.log(error);
两个关键点:
第一: 使用offsets数组作为记录,起到请求更多的作用。
第二: 使用process数组作为记录,起到防止发出多次请求的作用。
遇到的坑:
使用 document.body.clientHeight 和 document.documentElement.clientHeight 得到的高度并不是浏览器的高度(我在vue中确实是这样)。所以使用window.innerHeight 更好一些。 解决方法: 设置 html,body{width: 100%; height: 100%} 可以解决此问题。
使用zepto时,我用$("body").scroll(function () { // doSomeThing }) 时,发现并不奏效,这是因为通过查询api发现zepto并没有支持这个事件, 所以使用zepto时要注意: zepto并没有完全支持jquery的东西。
if ( typeof pageWidth != 'number' ) {
if (document.compatMode == 'CSS1Compat') {
pageWidth = document.documentElement.clientWidth;
pageHeight = document.documentElement.clientHeight;
} else {
pageWidth = document.body.clientWidth;
pageHeight = document.body.clientHeight;