热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

vue懒加载&&浏览器高度

当我们进入首页时,可能有很多条目需要显示,但是如果条目太多,我们全部将之显示出来就会造成性能的消耗,比如,我在第一条就找到了需要的或者我就看前面两条我就不想看后面的了,所以,这时候如果使用全部加载

  当我们进入首页时,可能有很多条目需要显示,但是如果条目太多,我们全部将之显示出来就会造成性能的消耗,比如,我在第一条就找到了需要的或者我就看前面两条我就不想看后面的了,所以,这时候如果使用全部加载的方式无疑是不合适的,比较好的做法就是首先显示一面多的内容,当检测到用户快要(或者已经)下拉到页面底部的时候我们再发出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')[0].scrollTop; // 如果在没有滚动的情况下就是0
let scrollHeight = $('body')[0].scrollHeight; // 即总的高度。如果在不超过一整页的情况下得到的也是
console.log(windowHeight + scrollTop);
console.log(scrollHeight);

if ((windowHeight + scrollTop) + 50 >= 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')[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 ) {
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的东西。 

 

 

获取高度。

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;
}
}

 

 

 

 

 

 

 


推荐阅读
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • 在C#中,使用关键字abstract来定义抽象类和抽象方法。抽象类是一种不能被实例化的类,它只提供部分实现,但可以被其他类继承并创建实例。抽象类可以用于类、方法、属性、索引器和事件。在一个类声明中使用abstract表示该类倾向于作为其他类的基类成员被标识为抽象,或者被包含在一个抽象类中,必须由其派生类实现。本文介绍了C#中抽象类和抽象方法的基础知识,并提供了一个示例代码。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • switch语句的一些用法及注意事项
    本文介绍了使用switch语句时的一些用法和注意事项,包括如何实现"fall through"、default语句的作用、在case语句中定义变量时可能出现的问题以及解决方法。同时也提到了C#严格控制switch分支不允许贯穿的规定。通过本文的介绍,读者可以更好地理解和使用switch语句。 ... [详细]
  • 移动端常用单位——rem的使用方法和注意事项
    本文介绍了移动端常用的单位rem的使用方法和注意事项,包括px、%、em、vw、vh等其他常用单位的比较。同时还介绍了如何通过JS获取视口宽度并动态调整rem的值,以适应不同设备的屏幕大小。此外,还提到了rem目前在移动端的主流地位。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 本文介绍了iOS开发中检测和解决内存泄漏的方法,包括静态分析、使用instruments检查内存泄漏以及代码测试等。同时还介绍了最能挣钱的行业,包括互联网行业、娱乐行业、教育行业、智能行业和老年服务行业,并提供了选行业的技巧。 ... [详细]
  • android 触屏处理流程,android触摸事件处理流程 ? FOOKWOOD「建议收藏」
    android触屏处理流程,android触摸事件处理流程?FOOKWOOD「建议收藏」最近在工作中,经常需要处理触摸事件,但是有时候会出现一些奇怪的bug,比如有时候会检测不到A ... [详细]
  • 涉及的知识点-ViewGroup的测量与布局-View的测量与布局-滑动冲突的处理-VelocityTracker滑动速率跟踪-Scroller实现弹性滑动-屏幕宽高的获取等实现步 ... [详细]
author-avatar
dnjaskn
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有