React开发实践6--详细说说滚动记忆

需求

我们的APP是一个电商hybrid APP!APP的几乎所有呈现部分,都由前端来完成。

首先说一下需求: 在17年的九十月份,接到业务部门的一些关于APP体验的反馈。其中一点是说用户在浏览首页的时候,点到某个商品详情里去,再返回的时候,并没有回到离开页面的位置,而是回到了页面的顶部,于是用户又需要重新从头开始浏览首页上的商品。为了更好地说明问题,他们还拿京东APP作为对比,比照了京东的体验,我才发现这一块的确有很大改进的空间。他只是举出了首页这一个示例,实际上在各个商品列表页也都有同样的问题。

#尝试找到核心问题

接到这个需求的时候,我其实有点茫然。搞不清楚这个问题的技术核心是什么,还专门去某乎提了一个问题手机京东web版用了什么技术能够让页面在刷新之后滚动到刷新之前的位置?(为了写这篇文,我又看了下这个答案的日志,我提问是在17年12月底) ,问题很快得到了回复:

这个是浏览器自带技能,无需手动实现。

我后来验证了一番,这果然是浏览器的自带技能。那么接下来问题又来了,为什么浏览器本身自带的技能,在我们开发的网站上就发挥不出来了呢?

经过了一番搜索之后,搞明白了这个道理。

浏览器在做什么

我们想一下这个过程,假如我们用电脑chrome浏览器打开一个小说阅读网站的阅读页,比如这个第40章 华山论剑,往下滚动使屏幕位置超过一屏,这个时候刷新页面,我们会发现浏览器记住了你刷新屏幕前的位置(上次阅读到的位置),于是你就可以继续阅读了,这是一个很赞的设计,浏览器帮助我们做到了。

接下来,我们打开一个购物网站,比如大名鼎鼎的某宝(https://www.taobao.com/),打开首页之后还是往下滚动,一直滚动到页脚的位置,刷新页面。有没有发现,虽然页面还是往下滚动了一下,但是并没有到达页脚的位置。这是为什么呢?

小说网站的阅读页,由于内容固定(当然固定了,反正就是这一章节的内容),直接把所有的内容写到了HTML中,于是我们解释一下刚刚的行为。假设浏览器是个人,比如chrome。

当然,做过前端开发的都知道,我们前端开发要面对的一大问题就是浏览器兼容性。因此在这里,我也必须要强调,我现在所说的chrome,是在linux系统内核下(包括Android)的chrome v55+,因为实际在测试中也发现很多国产手机浏览器比如小米MIUI内置的浏览器,或者是我自己魔趣8.1系统下内置的via浏览器都能够实现,前进回退记忆。(我先说一下我理解的前进后退记忆以及滚动记忆在本文中的意义。前进后退记忆即是说,当用户从A页面进入B页面,再返回到A页面,回到A页面不会触发任何网络请求,从A页面再回到B页面也不会触发任何网络请求。
)前进回退记忆是浏览器为了用户体验帮开发者做的一个工作,当回退的时候无需再去重复访问刚刚已经访问过的网址,不用加载前面已经加载过的内容。chrome 为什么原生不支持这个特性呢?我个人认为是chrome 还是想把这个自主权交给开发者。然而即便是像我前面提到的via浏览器,在处理history api来进行页面跳转的时候,在前进回退这件事上做得也并不够彻底。从我目前观察到的结论是:如果页面的跳转是通过a标签这样的方式来完成的(我可以认为他是真跳转,如果是真跳转,打开chrome的控制台,跳转的时候,勾选preserve log,跳转的时候会看到类似“Navigated to https://www.baidu.com/“ 这样的提示,假跳转则没有),这个时候via浏览器是可以实现页面的前进回退记忆的。反之,如果页面的跳转是通过history api来完成的(我可以认为他是假跳转),这个时候via浏览器认为需要把前进回退记忆这件事交给网站开发者自己来处理。

所以,前面我已经排除了很多干扰因素,也说明了这些干扰因素存在的原因。接下来,chrome虽然不支持前进后退记忆这件事,但是能够支持滚动记忆。也就是上面提到了例子,虽然它不支持前进后退的记忆,但是它支持滚动记忆,只要你在当前会话中有访问过某个页面,下次访问就还是会尽量自动滚动到上次滚动到的位置。

我接下来就聊一聊这个滚动记忆

我: 我把华山论剑这章看到了当前页面距离页顶8000px的位置,你知道的吧?
chrome: 我知道的亲
我:我要刷新页面喽
chrome: 好的,再你刷新页面之后,我还把华山论剑这章帮你滚动到距离页顶8000px的位置,好让你继续看接下来的情节
我:谢谢了,我刷新了
chrome: 我滚完了
我:我看到了,谢谢你。这个大结局很精彩

可是再看看某宝的反映呢?

我: 我已经看到了淘宝网页脚距离页顶8000px的位置了,你知道的吧?
chrome: 我知道的亲
我:我要刷新页面喽
chrome: 好的,再你刷新页面之后,我还把淘宝网页脚距离页顶8000px的位置了,好让你继续剁手
我:谢谢了,我刷新了
chrome: 我开始干活了。啊,等等,你当前淘宝页面只有4000px啊,抱歉,那我只能给你滚动4000px的位置了。
我:你明明知道我上次浏览这个页面的时候还有至少8000px呢,干嘛不等等,等Javascript把页面其他内容补充上,就有不止8000px了。
chrome: 亲,帮你滚动到上次浏览的位置,这个工作啊,我一回只能做一次。你不是想靠Javascript来补充HTML的内容么!那你就别来求我了。

我认为就是这么个过程,简单总结一下。浏览器会在从加载到load完成这个过程来做「滚动到上次浏览位置」这件事。而如果你的页面并非纯HTML写的,而是通过JS来插入节点完成的,就的确会出现刚才某宝网那样的问题。

React在做什么

知道了这样一件事,那么我们来看看我们的问题。现在先不谈首页,我们只说商品列表。从商品列表页到达某个商品详情页,然后再从详情页返回到商品列表页,我们来看看这个时候各个组件生命周期的变化。

首先,如果/productlist这个路由切换到/product:productId这个路由

组件 生命周期
Productlist willUnmount
Product didmount

而如果通过触发返回,从/product:productId这个路由切换到/productlist这个路由呢?

组件 生命周期
Productlist didmount
Product willUnmount

可以看到,Productlist 组件每次都需要进入一个新的生命周期。众所周知,为了更好的用户体验。我们往往会在页面中数据请求和处理的过程中,给用户一个loading的效果,因此用户每次返回后最先看到的都是loading,而不是展示的商品列表。

看到问题了吗?

在React的设计中,一个组件mount的时候(第一次render),就会把当时的组件内容渲染好后作为HTML进行输出,而之后这个组件update的过程,我们都可以理解为是React源码最终通过JS向DOM中插入节点或删除节点。于是,我们写的React页面反映出来的效果就是下面这样的:

我: 我已经看到了商品列表页面,距离页顶8000px的位置了,你知道的吧?
chrome: 我知道的亲
我:我进入了A商品的详情页,你记得等我回到商品列表页的时候,给我滚到刚才我离开前的位置
chrome: 好的
我: 我要回到商品列表页了
chrome: 我知道你的意思。我要干活了。。。等等,这个商品列表页只有一屏的高度。是个loading页面,不好意思,我不能继续向下滚了。
我:为什么
chrome: 我前面不是跟你解释过了么,还来问我

我能做什么

前面说了这么多,解决办法是什么呢?其实类似于我前面写的《React开发实践--4嵌套路由的应用》

最后

如果读者朋友能够看到这里,稍微有点质疑精神的朋友都会说,你说了这么一大堆,我凭什么相信你呢?
好吧,干货来了。
Here’s the Scroll Restoration Spec.
, 当然了,这其实也只是一个草案,可以看出来,各家浏览器对这个滚动的行为应该怎么处理,还没有达成一致。但是从前面我提到过的chrome,via浏览器,MIUI内置浏览器可以看出来,他们所表现出来的行为总体还是很接近这个草案的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,544评论 25 707
  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    X先生_未知数的X阅读 15,934评论 3 118
  • 书籍选择:《不要因为走得太远而忘记为什么出发》 planA:一周最后一天交笔记,三千字,每天上下班地铁上阅读,至少...
    何以笙歌阅读 352评论 0 0
  • 你的目标究竟离你多远 寒假将至,有不少学校已经开始放假,仅留下我们学校才刚刚进入考试周,校内的自习室是...
    山东水利职业学院专题阅读 54评论 0 0
  • 今天早上起床,反思今年圣诞节和主的关系似乎没有什么感情一样!为此心里有一点点的不美气,我开始省察自己……太磨叽?不...
    Esther书简阅读 642评论 0 0