当我们进入首页时,可能有很多条目需要显示,但是如果条目太多,我们全部将之显示出来就会造成性能的消耗,比如,我在第一条就找到了需要的或者我就看前面两条我就不想看后面的了,所以,这时候如果使用全部加载的方式无疑是不合适的,比较好的做法就是首先显示一面多的内容,当检测到用户快要(或者已经)下拉到页面底部的时候我们再发出ajax请求来请求更多的内容。

  

那么,第一步需要做的工作就是如何判断何时用户将页面拉到了底部。

  body是滚动的wrap,我们可以获得浏览器的高度、body的scrollTop、以及body的scrollHeight, 如果浏览器的高度 + body的scrollTop接近(达到)body的scrollHeight的值得时候,那么说明快要达到底部了。

如何获取浏览器的高度:

function getViewportSize () {
return {
width: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
height: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
};
}

这里使用 window.innerWidth 可以准确的获取到浏览器的宽度,通过 window.innerHeight 可以准确的获取到浏览器的高度。

但是当用户缩放时,window.innerWidth和window.innerHeight的值都会发生变化。其他的也是一样的。

只是我在做微信网页的时候发现,两者的值时不同的,只有 window.innerHeight才能获取到准确的值,

可以看到,这时的body并没有占满一页,所以这时获得的高度必然不是浏览器的高度。 值得注意,至于为什么,后续我会继续研究。

        let windowHeight = window.innerHeight; // 1334px
let scrollTop = $('body')[].scrollTop; // 如果在没有滚动的情况下就是0
let scrollHeight = $('body')[].scrollHeight; // 即总的高度。如果在不超过一整页的情况下得到的也是
console.log(windowHeight + scrollTop);
console.log(scrollHeight); if ((windowHeight + scrollTop) + >= scrollHeight) {
console.log("start");
}

如上所示: 我们使用 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')[].scrollTop; // 如果在没有滚动的情况下就是0
let scrollHeight = $('body')[].scrollHeight; // 即总的高度。如果在不超过一整页的情况下得到的也是
console.log(windowHeight + scrollTop);
console.log(scrollHeight); if ((windowHeight + scrollTop) + >= scrollHeight) {
console.log("start ajax request");
}
});

注意: 这里加 50 还是加一个别的数字,这是一个技巧,要根据情况进行设定, 比如我们希望还没有到底就可以开始加载更多了,就可以多加一些,如果希望到底部才加载更多,就设置加10或者5甚至不加都是可以的。

第三步就是需要开始请求更多的数据了

      if ((windowHeight + scrollTop) +  >= 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] + )
}
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')[].scrollTop;
let scrollHeight = $('body')[].scrollHeight;
console.log(windowHeight + scrollTop);
console.log(scrollHeight); if ((windowHeight + scrollTop) + >= 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] + )
}
// 表示正在进行中时,不再请求,
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": ,
"sbid": ,
"catalog3": contentObj.id,
"offset": contentObj.offset,
"pageSize":
}; axios.post('/bbg/goods/get_goods_list_wechat', qs.stringify({"data": JSON.stringify(content)}))
.then(function (response) {
if (response.data.code == ) {
if (response.data.data.length > ) {
var a = ;
for (let i = ; i < response.data.data.length; i++) {
var obj = {
index: contentObj.index,
item: response.data.data[i]
};
commit(UPDATE_CONTENT, obj);
a++;
}
if (a == ) {
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的东西。

获取高度。

var pageWidth = window.innerWidth,
pageHeight = window.innerHeight; 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;
}
}

vue懒加载 && 浏览器高度的更多相关文章

  1. 关于Vue懒加载问题

    有关Vue懒加载其实并不是想象的那么难和复杂: 首先引入 import  VueLazyLoad from 'vue-lazyload'; 其次是使用 Vue.use(VueLazyLoad,{ er ...

  2. vue懒加载

    vue懒加载(白屏或者加载慢的解决方法) 懒加载:也叫延迟加载,即在需要的时候进行加载,随用随载. 为什么需要懒加载? 像vue这种单页面应用,如果没有应用懒加载,运用webpack打包后的文件将会异 ...

  3. vue懒加载 路由 router 的编写(resolve)

    如果用import引入的话,当项目打包时路由里的所有component都会打包在一个js中,造成进入首页时,需要加载的内容过多,时间相对比较长.当你用require这种方式引入的时候,会将你的comp ...

  4. vue-lazyload 的vue 懒加载的使用

    vue-lazyload vue 图片懒加载的使用 下载 vue-lazyload npm i vue-lazyload -S 使用 vue-lazyload 在 src 下面的 main.js 的文 ...

  5. 使用Webpack的代码分离实现Vue懒加载(译文)

    当一个Vue的项目体积变得十分庞大的时候,使用Webpack的代码分离功能将Vue Components,routes或Vuex的代码进行分离并按需加载,会极大的提高App的首屏加载速度. 在Vue的 ...

  6. 使用Webpack的代码分离实现Vue懒加载

    当一个Vue的项目体积变得十分庞大的时候,使用Webpack的代码分离功能将Vue Components,routes或Vuex的代码进行分离并按需加载,会极大的提高App的首屏加载速度. 在Vue的 ...

  7. vue懒加载实现

  8. 原生js开发,无依赖、轻量级的现代浏览器图片懒加载插件,适合在移动端开发使用

    优势 1.原生js开发,不依赖任何框架或库 2.支持将各种宽高不一致的图片,自动剪切成默认图片的宽高 比如说你的默认图片是一张正方形的图片,则各种宽度高度不一样的图片,自动剪切成正方形. 完美解决移动 ...

  9. vue 路由懒加载 使用,优化对比

    vue这种单页面应用,如果没有应用懒加载,运用webpack打包后的文件将会异常的大,造成进入首页时,需要加载的内容过多,时间过长,会出啊先长时间的白屏,即使做了loading也是不利于用户体验,而运 ...

随机推荐

  1. [算法基础]Big O Notation时间复杂度计算方法

    首先一点就是无视任何常量 从最简单的开始 statement; 这段时间复杂度为常数1,所以O(1). 然后 ; i < N; i++ ) statement; 这一段是线性的,则时间复杂度为N ...

  2. spring的一些配置和重要的接口和类

    spring的配置文件 通常是applicationContext.xml(具体的bean配置会在后面内容中详解) setter方法注入: <property name=“” value=“ja ...

  3. 小度wifi在window server2008R2系统下创建不了

    小度wifi在window server2008R2系统下创建的时候会一直显示正在创建,然后又消失的情况.这是因为win server 2008下默认的无线lan服务没开启 解决方法: 在“服务管理器 ...

  4. mvc - codefirst 数据迁移

    from :http://blog.csdn.net/xiaoyiyz/article/details/41485325

  5. D:大整数的加减乘除

    描述 给出两个正整数以及四则运算操作符(+ - * /),求运算结果. 输入第一行:正整数a,长度不超过100第二行:四则运算符o,o是“+”,“-”,“*”,“/”中的某一个第三行:正整数b,长度不 ...

  6. javascript正则表达式——元字符

    元字符(Metacharacter)是拥有特殊含义的字符: 元字符        描述 (1)   .             查找单个字符,除了换行和行结束符. 例子: <!DOCTYPE h ...

  7. Nginx 进行性能配置

    总所周知,网络上我们购买的服务器的性能各不相同,如果采用 Nginx 的默认配置的话,无法将服务器的全部性能优势发挥出来,我们应该选择适合自己需求的配置. 当我们默认安装后 Nginx 后,我们便得到 ...

  8. mysql主从服务器

    #mysql主从服务器 mysql-bin.003673 | 106 查看错误日志show variables like '%log_error%'; replicate-do-table=testm ...

  9. 【BlockingQueue】BlockingQueue 阻塞队列实现

    前言: 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便 ...

  10. linux操作之文本编辑器

    1.文本编辑器的作用 编辑和修改系统中的那些以文本形式存在的文件(特别是各种配置文件),也可以用于 编写程序代码 2.linux下的常见编辑器 nano.Emacs.gedit.vim等 3.vim三 ...