【问题标题】:How to listen for changes to window.location.search in 2019如何监听 2019 年 window.location.search 的变化
【发布时间】:2019-09-21 11:07:11
【问题描述】:

我想更新window.location.search 而不重新加载文档,然后根据window.location.search 中的更新值执行一个函数。

当用户点击一个按钮时,该按钮的onclick 事件会触发以下函数:

window.history.pushState({action : 'myAction'}, document.title, '?action=myAction');

到目前为止一切顺利。浏览器 URL 栏中的 window.location.search 更新。

但我找不到检测此更新的通用后台事件侦听器 - 类似于 onhashchange 但用于查询字符串。

我能想到的最好的是:

window.history.pushState({action : 'myAction'}, document.title, '?action=myAction');
window.history.pushState({action : 'myAction'}, document.title, '?action=myAction');
window.history.back();

window.addEventListener('popstate', () => console.log(event.state.action));

这行得通,但我相信一定有更优雅的方法。

【问题讨论】:

    标签: javascript html query-string pushstate popstate


    【解决方案1】:

    最终答案:

    我对下面的第二次尝试回答非常满意。

    但我真的不喜欢:

    history.back();
    history.forward();
    

    我采用它来手动触发popstate 事件。

    在实践中,我发现这种 hack 有时会奏效,有时会很慢,有时会完全失败。

    在纸面上,感觉太临时了。

    经过反复搜索和试验(这非常难找到),我终于找到了手动触发 popstate 事件的正确语法。

    就像dispatching这个简单一样:

    new Event('popstate')
    

    像这样:

    let myEvent = new Event('popstate');
    window.dispatchEvent(myEvent);
    

    所以最后的代码是:

    window.history.pushState({action : 'myAction'}, document.title, '?action=myAction');
    let queryStringChange = new Event('popstate');
    window.dispatchEvent(queryStringChange);
    

    我能想到的最佳答案(第二次尝试):

    基于以下内容:

    我确定查询字符串将只需要检查

    1. 页面加载或重新加载时;

    2. window.history.pushstate 被调用时;

    3. 或者当(正如 @Kaiido 在下面的 cmets 中敏锐地指出)通过前进和后退按钮访问页面时

    我也知道:

    • window.load 事件侦听器涵盖第 1 点;
    • window.popstate 事件侦听器涵盖第 3 点。;

    只剩下第 2 点。


    处理第 2 点

    正如 MDN 报告的那样:

    请注意,只需调用 history.pushState()history.replaceState() 不会触发 popstate 事件。 popstate 事件将被触发 通过执行浏览器操作,例如单击后退或前进 按钮(或在 JavaScript 中调用 history.back()history.forward())。

    来源: https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event

    但这意味着,而不是使用(如下我第一次尝试):

    window.history.pushState({action : 'myAction'}, document.title, '?action=myAction');
    
    checkQueryString(); // DIRECT INVOCATION OF FUNCTION
    

    我可以改用:

    window.history.pushState({action : 'myAction'}, document.title, '?action=myAction');
    history.back();
    history.forward();
    

    这意味着不需要直接调用该函数,我现在可以允许覆盖 第 3 点 的相同 window.popstate 事件侦听器完成其工作,从而为我提供更清晰、逻辑上更分离的代码。


    注意我觉得……很奇怪……单独按下前进按钮触发window.popstate事件监听器,但调用window.history.pushState()不会...(需要立即添加 history.back(); history.forward(); 以复制前进按钮的功能)。

    但是,如上所述,这是我能想到的最好、最干净、最优化(就逻辑分离和未来代码维护而言)的解决方案。如果有人有更好的主意,我会很乐意转移绿勾。


    第一次尝试回答:

    我暂时得出结论,没有办法使用可以检测查询字符串何时更新的后台事件侦听器来实现此效果。

    相反,因为我知道肯定查询字符串将只需要检查

    • 页面加载或重新加载时
    • window.history.pushstate 被调用时

    我可以使用以下内容:

    window.addEventListener('load', checkQueryString);
    

    window.history.pushState({action : 'myAction'}, document.title, '?action=myAction');
    
    checkQueryString();
    

    【讨论】:

    • 您还需要监听popstate 事件,以便捕捉用户何时浏览浏览器的后退按钮。
    • 是的,很好。谢谢你抓住那个。那么两个事件监听器 - 一个用于load,一个用于popstate。如果您想将其作为替代答案发布,我很高兴将您改进的解决方案标记为已接受的答案。
    • 使用window.dispatch(myEvent)和使用history.back()有区别吗?使用window.dispatch(myEvent) 会改变history 对象吗?
    • 是的,有区别。 history.back()(和history.forward())将同时操作history 对象并更改地址栏中的url。对我来说,这些都是不受欢迎的副作用。在我对window.history 使用pushstate 方法之后,我只想让onpopstate 事件在window 上触发。
    猜你喜欢
    • 2020-03-12
    • 2021-09-21
    • 1970-01-01
    • 2017-11-18
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    • 1970-01-01
    • 2023-04-07
    相关资源
    最近更新 更多