页面事件和锚点问题

公司最近安排的一个小工作,解决两个页面上的小问题。问题1,带hash的链接跳转至目标页面后会发生抖动;问题2,IOS Safari浏览器回退后tab页效果失效。

情景描述

详细阐述问题。

问题1

假设有2个页面,一个新闻列表页面,一个是将列表中的所有新闻聚合在一起的一个新闻详情页面。

新闻列表点击通过链接跳转至详情页,同时通过hash来定位跳转后的位置。伪代码如下:

1
2
3
4
5
6
7
<!-- page1 -->
<a href="page2.html#foo">foo</a>
<a href="page2.html#bar">bar</a>

<!-- page2 -->
<a name="foo">foo</a>
<a name="bar">bar</a>

实际情境是详情页新闻特别多,上百条,是通过服务器渲染的数据。但是在跳转至详情页后,会发生页面先展示最顶端,然后再定位至应该定位的位置的情况。

起初我以为是因为内容太多,导致解析速度降低。

我写了简单的demo,生成了10000个链接。实际使用在跳转定位时候并没有发生抖动的问题。只是有可能因为DOM节点太多引起浏览器崩溃 - -!。

顺便搜索了一下资料,学习了些关于hash的知识,整理如下:

  • URL中的#字符代表页面上的位置,是指定位置标识符,取id的意思。
  • #可以定位到2种位置,1是有对应name属性的位置,2是有对应id属性的位置。使用name属性只能使用a标签。
  • #符号只供浏览器定位使用,在和服务器的HTTP交互中,hash字段内容并不会被发送。
  • 改变#符号后的内容不会引起浏览器页面的重载,只会让页面跳转至对应的位置。
  • 改变#符号后的内容会改变浏览器的历史记录。会在history API中新增内容,并且可以使用浏览器的回退按钮进行回退操作。(不包括IE6和IE7) Vue Routerhash模式就是基于这一特性的。
  • 通过window.location.hash可以读取hash值,IE8+存在hashchange事件可检测此变动。
  • 谷歌默认不抓取#部分的内容,但是可以使用#!将其后面的内容转成查询字符串_escaped_fragment_的值 。
  • 在页面按下F5后,即使url后面跟随有锚点,页面不会重新进行定位。这被称为锚点失效问题。

问题2

问题2描述很简单,就是简单的浏览器发生回退后tab效果失效了,但是页面简单地发生滚动就会重新生效。

感觉是页面暂时处于后台了,在一个未被激活的状态,所以它的事件失效了。

查询了一下页面隐藏显示切换的API,有两种事件pageshow/pagehidevisibilitychange

并且同时知道了如果a标签上面有target=_blank属性,点击后用新的标签页打开页面后,是不会有history记录的,也就是这时浏览器的回退是无效的。只有在同个页面内的跳转才会被history API记录。

visibilitychange事件监听的是这种标签处于前后台切换的事件。

pageshowpagehide则可以监听到浏览器的前进和回退,这种历史记录的事件。

两种事件的绑定方式也存在不同,方法如下:

1
2
3
4
5
// 绑定在document上
document.addEventListener('visibilitychange', e => {}, !1);

// 绑定在window上
window.addEventListener('pageshow', e => {}, !1);

兼容性

pageshow事件的兼容性为IE11+,详见:

CanIUse-pageshow

visibilitychange事件的兼容性为IE10+,详见:

CanIUse-visibilitychange

参考资料

阮一峰-URL的井号

MDN-pageshow

MDN-visibilitychange

有钱,任性!!!