见上述四张图的过程,图1为“记录列表页”,一开始打开“记录列表页”,滚到页面底部,选择最后一条记录,点击,会进入图3“记录详情页”,然后后退,就可以无刷新切换页面。做法很简单:
①“记录列表页”
; "记录详情页" ;②进入页面后,location.hash = "record";然后$("#record").show(); $("#detail").hide();
③点击某条记录会进入详情页,在点击方法里,location.hash = "detail";
④这时由于hash改变就会触发hashchange,这时写个方法,根据hash值去判断显示哪个页面
window.onhashchange = function() {
var viewName = location.hash.replace("#", "");
weixinArtificialPrice.showView(viewName);
};
至此用hash无刷新切换页面已经完成。但事情总是没那么简单,有个很重要的问题,因为,当初点进详情页的时候,是在最后一条记录点进去的,按道理说,返回来应该也在同样的位置,但是,竟然回去顶部了!对比图2与图4!
所以,现在重点问题来了:为什么用hash开发无刷新切换页面返回时滚动条会回到顶部?其实为什么会这样也很好理解,hash这东西其实相当于平时用的锚点,就是在你的URL后面加了“#XXX”,如果你页面没有id为XXX这个元素,浏览器自动会回到顶部。那怎样解决呢?
想法一:因为返回记录页的时候会回到顶部而不是原来的位置,那我在进入详情页面之前获取一下当前的位置,返回的时候设置回这个位置不就好了吗?
①进入详情页面前获取当前位置var scrollTop=$(window).scrollTop();
②返回来的时候设置回刚才保存的位置$(window).scrollTop(scrollTop);
想想这样应该可以手工了,殊不知,这下返回手机看起来卡得不行!点进去返回来都会闪烁……这下用户体验是极差的……为什么会这样?当时怎么想都想不通,还跑去知乎问了这个问题https://www.zhihu.com/question/41626149/answer/91758167 终于有一个大神给了思路,他说:因为这其中实际上有很多工作,需要 restyle 才能确定 CSS 规则,然后 layout 决定各种高宽 ,然后 composite 分出好几层来给用户看见,然后你才能设定 .scrollTop,如 果你没有用到 forced synchronous layout,就有可能会中间有几帧被用户看见了。建议 1. 用 scrollable container 局部滚动条代替 window 滚动条;2. 切换显示区域时不销毁滚动区域。
这段话对于一个新手来说简直信息量巨大,我真的不知道他说什么……只好拼命去查,后来终于知道,show() hide()这种显示隐藏的方式,是会使整个页面重绘的,而且,当页面显示出来之后,你再去设置滚动条的位置,这样一来又会重绘一次,这时肯定会卡。感兴趣的朋友可以查一下forced synchronous layout,用chrome调试工具中的TimeLine去测试页面的性能,他会告诉你,哪里是性能的瓶颈。
想法二:但即使知道这些,我当时还是没能理解大神的两条建议,我只是在想,既然是因为发生两次重绘才卡,那我如果能避免显示记录页时去重新设置滚动条的位置,那就解决了吧?
于是我去找,怎样才能又隐藏页面。又不会发生重绘。终于让我找到了方法,见张鑫旭大神的博客http://www.zhangxinxu.com/wordpress/2012/02/css-overflow-hidden-visibility-hidden-disabled-use/ 这篇文章会告诉你除了display:none还有什么方法隐藏元素还有各自的区别。于是我隐藏时用{ position: absolute; top: -999em; /* 不占据空间,无法点击 */ },显示的时候将top变为0。
果然,这样确实解决了问题。但项目里全部都是用show与hide,那我这样一改就要全部去改……这真的就是最好的方法了吗?
最终想法:滚动条会返回到顶部,本质上就是浏览器的滚动条作祟。
从想法二到现在最终的想法,期间遇到了其他的一些问题,比如区域滚动的问题,解决的之后回头再来想这个滚动条返回顶部的问题,就顿悟了。我们再来看大神的那两条建议:1. 用 scrollable container 局部滚动条代替 window 滚动条;2. 切换显示区域时不销毁滚动区域。上面的想法二其实本质上就是不销毁滚动区域,现在如果不想用这种方法,我们换个角度思考,其实之所以返回时滚动条会回到顶部,是浏览器的滚动条作祟,文章一开始说了“hash这东西其实相当于平时用的锚点,就是在你的URL后面加了“#XXX”,如果你页面没有id为XXX这个元素,浏览器自动会回到顶部”,所以我们怎样才能避免浏览器回到顶部呢?解决办法就是区域滚动,就是大神的第一点建议。这时我们就不需要去改变show hide这两个隐藏显示的方法,只需要在记录页的内容区域加上{overflow: auto;position: absolute;top: 0;bottom: 0;right:0;left: 0;},区域滚动的问题在文章“
补充想法:其实如果单纯是无刷新切换页面,强烈建议使用HTML5新方法history pushState去做,这样根本就没有上述的问题,因为是保存历史记录,你原来页面是什么样子后退之后当然还是什么样子。但是由于项目是基于微信企业号,经测试苹果手机没问题,安卓手机也照样返回顶部……所以就没用这种了……遗憾