【问题标题】:What are the differences between history.pushState & location.hash? [closed]history.pushState 和 location.hash 有什么区别? [关闭]
【发布时间】:2012-02-18 09:37:47
【问题描述】:

我想使用window.location.hashhistory.pushState 更新网址。

每种方法的区别和优势是什么?

【问题讨论】:

    标签: javascript html url pushstate fragment-identifier


    【解决方案1】:

    location.hashhistory.pushState 方法有更好的支持。

    pushState 方法的优点是您可以将状态绑定到历史记录条目。

    如果你不需要这个状态对象,我推荐使用location.hash 属性,以便更好地兼容旧版浏览器。

    location.hash = 'new-hash';
    console.log(history.state); // null or undefined
    
    history.pushState({extraData: "some state info"}, '', 'new-hash'); //<---
    console.log(history.state); // [object Object] = {"extraData": "some state info"}
    

    【讨论】:

    • 但是是否可以将 history.state 加入书签或将其发布到 facebook 上?我认为哈希是可能的。它们是完全不同的东西。
    • @Robert 当您为某些内容添加书签时,将使用当前在浏览器中看到的 URL。状态对象与历史条目相关联。因此,它仅在通过浏览历史导航到页面时可用(例如,浏览器关闭后的会话恢复)。一种方法不排除另一种方法:使用history.pushState('some long state cached from server', '', '/posts/id#prefix-some-specific-identifier') 是合法的,例如,如果应用程序确实需要它。在此示例中,缓存了服务器响应。顺便说一句,哈希也可以是斜线。
    • 啊,当然。所以你的回答真的很简单。 hash 支持更好,pushState 更强大。
    • 自从这个问题问了 3 年后,现在哪个更好,pushstate 还是 location.hash?
    • @hous history.pushStatehistory.replaceState 如果您确实需要将数据与历史条目相关联,请使用 history.state。如果您希望页面状态可收藏,那么location.hash 就足够了(因为书签只能存储页面 URL,不能存储历史状态)。
    【解决方案2】:

    Pushstate 是未来。更好,因为:

    1. 看起来更干净。
    2. 在重新访问深层链接时,您实际上可以显示真实的服务器端数据以支持诸如 SEO 和 Facebook Open Graph 之类的东西(两者都发送蜘蛛来抓取您网页的 html)。
    3. 服务器无权访问哈希标签数据,因此您不会在服务器日志中看到它,因此它可以帮助某些人进行分析。
    4. 它有助于解决哈希标签问题。例如,我进行了 Nginx 重写,以将访问我的应用程序的用户重定向到相同的 https url。它适用于所有浏览器,但 Safari 会将您重定向到没有哈希的域(太烦人了)!
    5. 实际上,您可以将哈希标记用于预期用途,深度链接到长页面的各个部分。
    6. 对于不支持推送状态的浏览器,您可以回退到使用真正的 HTTP 后端请求,或者您可以回退到使用哈希标记。两者都需要额外的实现,但只需一点点工作即可轻松实现。

    更多信息请参见 Github 设计师的演讲:http://warpspire.com/talks/responsive/

    【讨论】:

    • Pushstate 有一个小缺点:它强制服务器在第一次访问/当您在新选项卡中打开链接页面时为您呈现页面。如果一个人打开 10 个标签页(例如,浏览画廊并打开有趣的图片),它会比 hashbangs 慢得多,因为根本不使用 ajax。
    • @Hello-World:这是一个假设。对于许多/大多数基于 JavaScript 的框架,它所做的事情与 hashbangs 所做的完全相同。
    • 你能解释一下吗?假设我访问 example.com/ajax#gallery,我的浏览器通过 example.com/ajax 下载了一些 js,然后该 js 请求并呈现#gallery。当我在新选项卡中打开 example.com/ajax#image1 时,我的浏览器已经缓存了 example.com/ajax,因此它只需要获取 #image1 并呈现它。据我所知,Pushstate 并非如此。当您在新选项卡中打开 example.com/ajax/image1(pushstate)或第一次访问它时,浏览器必须下载整个页面,而不管 example.com/ajax 上的缓存如何。如果我错了,我愿意更正。
    • @Hello World:好的,你在技术上是对的。通常,当使用 pushstate 时,它​​会动态更改 URL,并且不会进行额外的页面加载。如果您右键单击并在选项卡中打开一个链接,您并没有真正利用动态推送声明的全部意义。单击 Facebook 流中的图像,记下动态 URL 更改,然后将 URL 粘贴到新窗口中。你刚才看到的比你提到的“缺点”要有利得多。在这种情况下,它实际上是一个好处而不是一个缺点。
    • (上下文:在 Facebook 中,图库是基于 ajax 的,单击照片会更改 URL 并放大该照片,将 URL 复制到新选项卡会加载照片的静态页面)。这不是更有利的。考虑这个替代方案:画廊位于 fb.com/#gallery-17。单击照片会放大照片并将 url 更改为 fb.com/#photo-521。打开多张照片时效率更高,因为 fb.com 始终被缓存。
    【解决方案3】:

    这是一个相当古老的问题(在此回复时已超过 5 年),但现有回复中的许多 cmets 都要求根据“当前”状态进行更新。

    这是交易:

    所有主流浏览器都支持 HTML5 的 pushState。如果你也支持旧版浏览器,history.js 提供了一个很棒的 polyfill,让你可以在本地使用 pushState 并轻松回退到旧版浏览器的旧版 URL。但是,现在原生支持 pushState 并不意味着它绝对是可行的方法。

    有一个非常重要的点,在任何较旧的答案中都没有提出,那就是哈希 URL 和 pushState URL 不仅在它们出现的方式上不同,而且它们在工作方式上实际上也不同.两者之间的这种根本区别可能会导致您选择其中一个。

    pushState 更漂亮、更简洁,可用于在您的网站/应用程序中完全伪造导航。例如,GitHub 使用它来无形地替换所有导航。当您点击他们网站上的任何链接时,javascript 用于拦截该点击并将其转换为更新页面内容而不加载新页面的 AJAX 请求,而位置栏中的 URL 会更改以匹配之前的内容获取。 这就是 pushState 的用途

    对于 GitHub,http://mysite/page1http://mysite/page2 都是有效的 URL。它们是带有“真实”内容的“真实”链接,并且最初访问任一页面都会通过传统的 MVC 方法。 GitHub 在现代浏览器中使用 pushState 进行导航,但不需要它 - 即 pushState 被用作“功能添加”(在他们看来)可以在导航方面带来更好的用户体验。当您复制浏览器地址栏中的链接时,您复制的是通过 javascript 和 pushState 形成的链接,但该链接仍然是真实有效的。

    但是,如果您是从头开始创建单页应用程序并且没有使用 MVC 框架,那么您实际上可能只有一个页面,特别是如果您没有使用动态后端(即内容就是所有通过 javascript 检索,从未由服务器生成)。在这种情况下,如果您在哈希 url 上使用 pushState,您将需要处理浏览器中的 URL 不是真实 URL 的情况。我会举例说明。

    用户加载你的单页应用:http://mysite/mainpage

    此时,浏览器栏包含指向您应用的真实链接,并将用户带到他们当前看到的相同视图:主页。现在,他们单击一个链接,该链接会将他们带到一个“页面”,其中显示了某些活动的详细信息。此时,您要更新位置栏以指示状态更改。你要么使用哈希 URL,你的地址栏看起来像 http://mysite/mainpage#charts/1,要么你使用 pushState 并欺骗它成为 http://mysite/mainpage/charts/1

    如果你使用了 pushState,那不是真正的链接。通过浏览器的后退/前进按钮导航将非常有用,用户将从主页转到位置栏和应用程序中的详细信息页面(假设您正确处理状态更改),但如果用户将此链接添加为书签或复制并粘贴链接以共享它,需要额外的服务器端 voodoo。

    您需要将请求重定向到 /mainpage/charts/1 到 /mainpage,然后使用 JS 解析实际 URL 并执行预期的状态更改操作。服务器重定向是绝对需要的。如果没有可编写脚本的 http 服务器,您无法在 AWS 或本地磁盘上托管此页面。

    现在,如果您使用哈希 url,那么用户会看到并与之交互的 URL 将是 http://mysite/mainpage#/charts/1 这是一个有效的、真实的 url。浏览器知道只有一页,无论用户复制和粘贴链接还是将其添加为书签,您只需要在 javascript 中处理哈希状态,不需要任何服务器端的魔法来使事情正常进行。

    似乎没有人提到的是,pushState 和 hash 链接并不是相互排斥的。 pushState 只是一个 API,用于操作用户可见的浏览器位置并在现代浏览器中实现可靠的后退/前进导航。它没有说明您的 URL 方案应该是什么样子。

    在 2017 年,Google 和几乎所有其他支持 JS 的机器人都可以很好地理解哈希 URL 并遍历它们。 Google 希望您使用 #!对 SEO 的厌恶 最大化目的,但即使您不这样做,您的网站也可以正常导航。

    正确的答案是使用最适合您需求的任何东西。如果你有真实的 URL 并且想在它们之间伪造导航,请使用 pushState 并继续(可选地使用旧浏览器的 polyfill)。但是如果你有一个单页应用程序,不要假装没有(除非你有很好的理由)。使用哈希 URL 让您的生活更轻松,并且不会引入不必要的问题然后使用 pushState 来操作这些哈希 URL 以利用更好的后退/前进支持

    【讨论】:

    • 我不确定你最后一句是什么意思:你是否建议用 location.hash 替换 URL,然后用 pushState 再做一次?那会有什么帮助?据我了解,pushState 的主要问题是书签,但如果我们这样做,我们最终不会得到需要重定向魔法的书签 URL 吗?顺便说一句,非常清晰和信息丰富,试图获取所有这些信息感觉就像是在拼一个难题,在这里你真的触及了与讨论相关的几乎所有内容,谢谢
    • @FabioLolli 关于最后一句话 - 在我的应用程序中,我有时会发现自己通过 pushStatereplaceState 操纵位置哈希。例如,最近的应用程序在按键上执行搜索。此搜索应该更新用于书签/转发等的 URL,但您不希望每次击键都用新条目填充历史堆栈(就像通过操作 location.hash 会发生的那样)。相反,我在打字时使用replaceState,然后在一些反跳超时或按回车键后,如有必要,请执行pushState
    • 实际上,截至 2015 年 10 月,Google 不希望您使用 #!。 webmasters.googleblog.com/2015/10/…
    【解决方案4】:

    history.pushState 优于 location.hash。但它是 HTML5 功能。所以最好有一个像下面这样的后备方法。

    if (typeof(window.history.pushState) == 'function') {
        window.history.pushState(null, path, path);
    } else {
        window.location.hash = '#!' + path;
    }
    

    【讨论】:

    • 自从这个问题问了 3 年后,现在哪个更好,pushstate 还是 location.hash?
    • 回退在这里没有意义:location.hash 在也支持 pushState 的浏览器上也能正常工作 - 如果你真的需要 pushState(因为你需要存储一个对象),那么 location.hash 不会不能作为后备。随便挑一个。
    【解决方案5】:

    我同意其他答案,但这里有一些论点赞成 location.hash:

    • 它适用于所有浏览器,包括 Internet ExploderTM
    • history.pushState 是一个正在开发的标准,API 将来可能会发生变化
    • 如果用户在新窗口/选项卡中打开链接,哈希 URL 可确保加载页面不需要服务器请求(如果设置了正确的缓存标头)
    • 服务器配置很简单,因为服务器看到的只是没有散列部分的 URL

    编辑:我忘记了一个

    • 使用主题标签,您可以使用真实链接 (a href)。因此您不必设置点击侦听器,从而提高性能并减少代码大小。

    【讨论】:

    • Google 将发送 #!基于哈希...这需要一些努力...为 photogallery.classiccars.com 做了这个
    • 是否有计划通过新标签让 Pushstate 变得更好?
    【解决方案6】:

    window.location.hash 与 HTML5 history.pushstate 的优缺点很大程度上取决于您希望页面降级的程度。

    在这里,您可能对两种不同场景中的优雅降级感兴趣:

    第一个是没有启用 javascript 的客户端,或者是访问您网站的自动爬虫程序/爬虫程序。从 SEO 的角度来看,这一点尤为重要。如果您的网页/网络应用程序使用哈希 URL,则这些最终用户无法使用通过这些链接获得的内容。如果您仅通过没有后备的哈希 URL 使部分内容可用,这绝对是一个问题。但是,如果您使用哈希标签链接来修改应用程序状态,这绝对不是问题,如果页面降级,它根本不会保留意义。

    例如,考虑这样一个场景,您的页面在选项卡式布局小部件的三个选项卡中提供了三个文本部分。现在有两种可能的情况:首先,您将在页面加载期间加载所有内容 - 选项卡式小部件将仅用于隐藏其他部分并显示特定部分。因此,如果您在用于构建选项卡缩略图的链接中使用哈希 URL,那么您只是在使用它们来更改客户端应用程序状态。当 javascript 关闭/不可用时,只是用于构建选项卡式布局的 javascript 不会运行,并且所有内容都立即可用 - 一个合理的优雅回退。在这种情况下根本不存在不同的应用程序状态,因此哈希 URL 降级为仅指向 html 中的锚点 - 预期目的。 如果您在这种情况下使用 html5 pushstate,而不是 hash-urls,那将是一个坏主意。用户可能会将指向特定选项卡的链接加入书签的原因。因为您的服务器必须采用该 url 并向用户呈现他所期望的客户端状态。这对于客户端应该处理自己的状态管理的瘦服务器架构来说是不利的。您当然可以忽略服务器端的这一方面,让客户端在页面加载时一开始就检查 url,然后切换到适当的应用程序状态。但这仍然不是一个好主意,因为您的服务器端路由系统关心它应该忽略的额外 url 片段的开销,因为从美学的角度来看,它根本不应该为那个片段而烦恼。这完全符合设计哈希 URL 的要求,强烈建议使用它们。如果改为在三个部分中,当单击特定的选项卡缩略图时,文本会动态加载,那么使用 hash-urls 不是一个好主意。原因是如果 javascript 不可用,用户将无法访问链接的内容。这对 SEO 尤其不利。在这种情况下,如果您在服务器端处理 url(在正常情况下会被“劫持”和“ajaxified”)以使内容通常可用,那么从最终用户体验和 SEO 的角度来看,它都是极好的。

    第二种情况是客户端的浏览器过时,不支持 html5 推送状态。尽管上述观点仍然成立,此外我还认为,强迫没有 pushstate 的用户与 no-javascript 具有相同的降级水平是不合理的。许多最终用户根本不知道他们为什么会收到降级版本。

    我建议您不要总是带着教条主义的动机使用最新技术,并根据您的使用场景确定最佳选择。

    【讨论】:

    【解决方案7】:

    目前,所有现代浏览器都支持pushState。因此pushStatelocation.hash 更好,但它是一个HTML5 特性。

    所以,location.hash 并没有死,实际上它会存在很长时间。

    使用它的一个好方法是使用支持pushState 的库,但也可以优雅地降级为使用location.hash
    示例 - https://github.com/browserstate/history.js

    此外,location.hash 仍可用于跳转到命名锚点。 pushState 将极大地帮助构建 Web 应用程序。我期待着使用它。

    【讨论】:

      【解决方案8】:

      我个人更喜欢 pushState,因为它使 URL 看起来更漂亮,我认为这对用户体验很重要。

      如果您想使用 pushState,但不想遇到旧版浏览器支持问题,您可以使用 history.pushState 和使用 history.js polyfill 的哈希回退。

      【讨论】:

      • 您的用户体验是由大多数用户甚至没有注意到的 # 决定的?
      【解决方案9】:

      我在这个帖子的任何地方都没有看到一个非常小的差异:

      设置window.location.hash 将强制立即滚动跳转到文档中的新哈希元素(至少在我拥有的浏览器中)。如果您想要平滑滚动,但还希望 url 栏中的哈希值更新/更改,则必须像这样使用window.history.pushState

      document.getElementById(id).scrollIntoView({ behavior: "smooth" });
      window.history.pushState(null, null, "#" + id);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-10
        • 2011-09-20
        • 2013-03-25
        • 2023-03-08
        • 2016-07-17
        • 2015-07-17
        • 2014-07-11
        • 2020-12-28
        相关资源
        最近更新 更多