Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

History #36

Open
lxy666 opened this issue Mar 5, 2019 · 0 comments
Open

History #36

lxy666 opened this issue Mar 5, 2019 · 0 comments

Comments

@lxy666
Copy link

lxy666 commented Mar 5, 2019

||

小明在微信里收到别人发的 「今日头条」 的一篇新闻,打开阅读之后,意外发现这个网页竟然可以后退到今日头条的首页。咦?明明打开的是一个网页呀,为什么历史记录能后退呢?这是用了什么黑魔法? 如果用在我们的 M站,好像也非常合适呢。

任务:

  • 调查实现原理

技能

javascript

gitlab m站测试分支 back_home
review

主要代码

function backHome(url) {
    if (history.length < 2) {
       const backState = {title: 'index',url: url};
       window.history.pushState(backState, 'index', location.href);
       const currentState = {title: 'index',url: ''};
       window.history.pushState(currentState, 'index', '');
    }
    window.addEventListener('popstate', () => {
        if (window.history.state != null && window.history.state.url != '') {
             location.href = window.history.state.url
         }
    });
}

History

History 对象属性。

History.length:只读的,其值为一个整数,标志包括当前页面在内的会话历史中的记录数量,比如我们通常打开一个空白窗口,length为0,再访问一个页面,其length变为1。

History.scrollRestoration: 允许web应用在会话历史导航时显式地设置默认滚动复原,其值为auto或manual。(auto: 默认,保留上一次的滚动条位置。manual: 滚动条位置为初始化位置(垂直方向置顶,水平方向最左边))

History.state:只读,返回代表会话历史堆栈顶部记录的任意可序列化类型数据值,我们可以以此来区别不同会话历史纪录。

History.back()、History.forward()、History.go()

History.back():移动到上一个网址,等同于点击浏览器的后退键。对于第一个访问的网址,该方法无效果。

History.forward():移动到下一个网址,等同于点击浏览器的前进键。对于最后一个访问的网址,该方法无效果。

History.go():接受一个整数作为参数,以当前网址为基准,移动到参数指定的网址,比如go(1)相当于forward(),go(-1)相当于back()。如果参数超过实际存在的网址范围,该方法无效果;如果不指定参数,默认参数为0,相当于刷新当前页面。

History.pushState()

History.pushState()方法用于在历史中添加一条记录。

window.history.pushState(state, title, url)

该方法接受三个参数,依次为:

  • state:一个与添加的记录相关联的状态对象,主要用于popstate事件。该事件触发时,该对象会传入回调函数。也就是说,浏览器会将这个对象序列化以后保留在本地,重新载入这个页面的时候,可以拿到这个对象。如果不需要这个对象,此处可以填null。
  • title:新页面的标题。但是,现在所有浏览器都忽视这个参数,所以这里可以填空字符串。
  • url
    1. 此参数声明新添会话记录的入口URL;
    2. 在调用pushState()方法后,浏览器不会加载URL指向的页面(在重启浏览器后或许会加载新页面 ),我们可以在popstate事件回调中处理页面是否加载;
    3. 此URL必须与当前页面URL同源,,否则会抛异常;其值可以是绝对地址,也可以是相对地址,相对地址会被基于当前页面URL解析 得到绝对地址;若其值为空,则默认是当前页面URL。

pushState()方法可以改变URL地址栏,在会话历史堆栈顶部插入一条新会话记录,如:

var stateObj = { foo: 'bar' };
history.pushState(stateObj, 'page 2', '2.html');

添加新记录后,浏览器地址栏立刻显示example.com/2.html,但并不会跳转到2.html,甚至也不会检查2.html是否存在,它只是成为浏览历史中的最新记录。这时,在地址栏输入一个新的地址(比如访问google.com),然后点击了倒退按钮,页面的 URL 将显示2.html;你再点击一次倒退按钮,URL 将显示1.html。

总之,pushState()方法不会触发页面刷新,只是导致 History 对象发生变化,地址栏会有反应。

使用该方法之后,就可以用History.state属性读出状态对象。

var stateObj = { foo: 'bar' };
history.pushState(stateObj, 'page 2', '2.html');
history.state // {foo: "bar"}

如果pushState的 URL 参数设置了一个新的锚点值(即hash),并不会触发hashchange事件。反过来,如果 URL 的锚点值变了,则会在 History 对象创建一条浏览记录。

如果pushState()方法设置了一个跨域网址,则会报错。

// 报错
// 当前网址为 http://example.com
history.pushState(null, '', 'https://twitter.com/hello');

上面代码中,pushState想要插入一个跨域的网址,导致报错。这样设计的目的是,防止恶意代码让用户以为他们是在另一个网站上,因为这个方法不会导致页面跳转。

History.replaceState()

History.replaceState()方法用来修改 History 对象的当前记录,其他都与pushState()方法一模一样。

假定当前网页是example.com/example.html。

history.pushState({page: 1}, 'title 1', '?page=1')
// URL 显示为 http://example.com/example.html?page=1

history.pushState({page: 2}, 'title 2', '?page=2');
// URL 显示为 http://example.com/example.html?page=2

history.replaceState({page: 3}, 'title 3', '?page=3');
// URL 显示为 http://example.com/example.html?page=3

history.back()
// URL 显示为 http://example.com/example.html?page=1

history.back()
// URL 显示为 http://example.com/example.html

popstate 事件

每当同一个文档的浏览历史(即history对象)出现变化时,就会触发popstate事件。

注意,仅仅调用pushState()方法或replaceState()方法 ,并不会触发该事件,只有用户点击浏览器倒退按钮和前进按钮,或者使用 JavaScript 调用History.back()、History.forward()、History.go()方法时才会触发。另外,该事件只针对同一个文档,如果浏览历史的切换,导致加载不同的文档,该事件也不会触发。

使用的时候,可以为popstate事件指定回调函数。

window.onpopstate = function (event) {
  console.log('location: ' + document.location);
  console.log('state: ' + JSON.stringify(event.state));
};

// 或者
window.addEventListener('popstate', function(event) {
  console.log('location: ' + document.location);
  console.log('state: ' + JSON.stringify(event.state));
});

回调函数的参数是一个event事件对象,它的state属性指向pushState和replaceState方法为当前 URL 所提供的状态对象(即这两个方法的第一个参数)。上面代码中的event.state,就是通过pushState和replaceState方法,为当前 URL 绑定的state对象。

这个state对象也可以直接通过history对象读取。

var currentState = history.state;

注意,页面第一次加载的时候,浏览器不会触发popstate事件。

Can I use

Method of manipulating the user's browser's session history in JavaScript using history.pushState, history.replaceState and the popstate event.

作用

作用: 劫持到用户返回操作后, 可以返回到首页,对网站的PV增长起到了很大的作用。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant