【问题标题】:All-in-one location/hashchange history management library多合一位置/哈希更改历史管理库
【发布时间】:2012-07-10 18:03:44
【问题描述】:

首先,我知道有些库为location.pushState/popStateHistory.jsHash.jsjQuery hashchange)提供了 polyfill,所以请不要只链接到这些。

我需要一个更强大的库来在 RIA 中实现以下目标:

  1. 用户点击链接
  2. 通过 Ajax 通知库并加载上下文(没有完全重新加载!)
  3. 所有<a> 元素都与单击处理程序一起使用,该处理程序
    • 防止在 2. (preventDefault) 中重新加载页面和
    • 为旧版浏览器调用 location.pushState / 设置 location.hash
  4. 加载的内容插入页面并替换当前内容
  5. 继续 1。

此外,之前加载的内容应在用户返回时恢复。

例如,在 Internet Explorer Google+。

有什么比这更接近的吗?我需要对 IE8、FF10、Safari 5 和 Chrome 18 的支持。此外,它应该具有 MIT 或 Apache 等许可许可证。

【问题讨论】:

  • 作为旁注,Google+ apparently uses their Closure library,但似乎涉及很多手动操作。
  • 您希望它如何处理表单提交或其他非 GET 请求?
  • @ScottSauyet 我没有考虑过。猜猜这是一个不同的故事,但如果有一个解决方案也能涵盖这一点,我会非常高兴。
  • @Pumbaa80,对于我提供的答案,您可以通过addToHistory(id, data, title, url, options); 方法手动将任何内容添加到历史记录中。在表单提交期间,使用该 AjaxTCR 库 API 方法来处理这些非缓存的历史位置/对象。
  • 您不需要库,我相信您提到的其中一个库 + 100 行 js 可以完成这项工作

标签: cross-browser javascript browser-history


【解决方案1】:

我相信 Sammy.js (http://sammyjs.org)(获得 MIT 许可)最专注于您想做的事情,它的两个主要支柱是:

  1. 路线
  2. 活动

我可以引用文档,但这很简单:

  • 设置与待办事项相关的客户端路由,例如:通过 ajax 更新视图

  • 链接事件来调用路由,例如:当我点击一个链接时调用上面的路由。 (您必须确保在我相信的已定义事件中调用 e.preventDefault,因为这确实是一个应用程序决定,因此您将使用恕我直言的任何库都无法将其抽象出来)

一些相关文档

路由示例:(来自http://sammyjs.org/docs/tutorials/json_store_1

 this.get('#/', function(context) {
    $.ajax({
      url: 'data/items.json',
      dataType: 'json',
      success: function(items) {
        $.each(items, function(i, item) {
          context.log(item.title, '-', item.artist);
        });
      }
    });
  });

或者类似的东西

 this.get('#/', function(context) {
     context.app.swap(''); ///the 'swap' here indicates a cleaning of the view
                              //before partials are loaded, effectively rerendering the entire screen. NOt doing the swap enables you to do infinite-scrolling / appending style, etc. 
     // ...
   });

当然,其他客户端 MVC 框架也可以是一种选择,它可以消除更多的管道,但在这种情况下可能会过度杀伤力。

一个很好的(而且仍然是最近的)比较:

http://codebrief.com/2012/01/the-top-10-javascript-mvc-frameworks-reviewed/ (我自己使用 Spine.js)。

最后,我认为在客户端刷新等中包含我刚才写的一个答案可能很有用,该答案详细介绍了整个最佳实践(如我所见)等。也许你找到有用:

Accessibility and all these JavaScript frameworks

【讨论】:

  • 我已经 +1 来补偿这样做的人。现在,Upvotes 是公平的。话虽如此,由于 OP 未能手动奖励完整的 +500,因此您似乎将获得 1/2 的赏金以获得最多的支持。干杯!
【解决方案2】:

我目前在我的一个应用程序中使用PathJS。 这是我做过的最好的决定。 对于您的特定用例,请查看HTML5 Example

使示例工作的代码片段(来自源代码):

<script type="text/javascript">
        // This example makes use of the jQuery library.

        // You can use any methods as actions in PathJS.  You can define them as I do below,
        // assign them to variables, or use anonymous functions.  The choice is yours.
        function notFound(){
            $("#output .content").html("404 Not Found");
            $("#output .content").addClass("error");
        }

        function setPageBackground(){
            $("#output .content").removeClass("error");
        }        

        // Here we define our routes.  You'll notice that I only define three routes, even
        // though there are four links.  Each route has an action assigned to it (via the 
        // `to` method, as well as an `enter` method.  The `enter` method is called before
        // the route is performed, which allows you to do any setup you need (changes classes,
        // performing AJAX calls, adding animations, etc.
        Path.map("/users").to(function(){
            $("#output .content").html("Users");
        }).enter(setPageBackground);

       Path.map("/about").to(function(){
            $("#output .content").html("About");
        }).enter(setPageBackground);

       Path.map("/contact").to(function(){
            $("#output .content").html("Contact");
        }).enter(setPageBackground);

        // The `Path.rescue()` method takes a function as an argument, and will be called when
        // a route is activated that you have not yet defined an action for.  On this example
        // page, you'll notice there is no defined route for the "Unicorns!?" link.  Since no
        // route is defined, it calls this method instead.
        Path.rescue(notFound);

        $(document).ready(function(){
            // This line is used to start the HTML5 PathJS listener.  This will modify the
            // `window.onpopstate` method accordingly, check that HTML5 is supported, and
            // fall back to hashtags if you tell it to.  Calling it with no arguments will
            // cause it to do nothing if HTML5 is not supported
            Path.history.listen();

            // If you would like it to gracefully fallback to Hashtags in the event that HTML5
            // isn't supported, just pass `true` into the method.

            // Path.history.listen(true);

            $("a").click(function(event){
                event.preventDefault();

                // To make use of the HTML5 History API, you need to tell your click events to
                // add to the history stack by calling the `Path.history.pushState` method. This
                // method is analogous to the regular `window.history.pushState` method, but
                // wraps calls to it around the PathJS dispatched.  Conveniently, you'll still have
                // access to any state data you assign to it as if you had manually set it via
                // the standard methods.
                Path.history.pushState({}, "", $(this).attr("href"));
            });
        });
    </script>

PathJS 具有路由库的一些最需要的特性:

  • 轻量级
  • 支持 HTML5 History API、'onhashchange' 方法和优雅降级
  • 支持根路由、救援方法、参数化路由、可选路由组件(动态路由)和面向方面编程
  • 经过良好测试(在 ./tests 目录中提供测试)
  • 兼容所有主流浏览器(在 Firefox 3.6、Firefox 4.0、Firefox 5.0、Chrome 9、Opera 11、IE7、IE8、IE9 上测试)
  • 独立于所有第三方库,但与所有第三方库都很好

我发现最后一点最吸引人。 你可以找到他们here

我希望你觉得这很有用。

【讨论】:

  • 请发表评论以帮助我理解为什么你给了我一个downvote
  • 我刚刚使用 pathjs 完成了一个项目,我对此非常满意。非常易于使用(并使其与 Google Analytics 一起使用)。这是一个极简主义的库,但它应该得到更好的文档。
【解决方案3】:

我想建议一个组合

crossroads.js 作为路由器 http://millermedeiros.github.com/crossroads.js/

以及用于处理浏览器历史记录和哈希 URL 的哈希器(带有大量后备解决方案): https://github.com/millermedeiros/hasher/ (基于http://millermedeiros.github.com/js-signals/

这仍然需要几行代码(加载 ajax 内容等),但在处理路由时会为您提供大量其他可能性。

这是一个使用 jQuery 的示例(以上库都不需要 jQuery,我只是懒惰......)

http://fiddle.jshell.net/Fe5Kz/2/show/light

HTML

<ul id="menu">
    <li>
        <a href="foo">foo</a>            
    </li>
    <li>
        <a href="bar/baz">bar/baz</a>
    </li>
</ul>

<div id="content"></div>

JS

//register routes
crossroads.addRoute('foo', function() {
    $('#content').html('this could be ajax loaded content or whatever');
});

crossroads.addRoute('bar/{baz}', function(baz) {

    //maybe do something with the parameter ...
    //$('#content').load('ajax_url?baz='+baz, function(){
    //    $('#content').html('bar route called with parameter ' + baz);
    //});

    $('#content').html('bar route called with parameter ' + baz);
});


//setup hash handling
function parseHash(newHash, oldHash) {
    crossroads.parse(newHash);
}
hasher.initialized.add(parseHash);
hasher.changed.add(parseHash);
hasher.init();


//add click listener to menu items
$('#menu li a').on('click', function(e) {
    e.preventDefault();
    $('#menu a').removeClass('active');
    $(this).addClass('active');

    hasher.setHash($(this).attr('href'));
});​

【讨论】:

    【解决方案4】:

    你看过微软的BigShelf sample SPA (Single Page Application) 吗?听起来它涵盖了如何实现您所要求的大部分内容。

    它利用 History.js,一个自定义的包装对象来轻松控制导航,称为 NavHistory 和 Knockout.js 用于点击处理。

    这是一个非常简短的工作流程:首先,您需要初始化一个 NavHistory 对象,该对象包装 history.js 并注册一个回调,该回调在推送状态或哈希更改时执行:

    var nav = new NavHistory({
        params: { page: 1, filter: "all", ... etc ... },
        onNavigate: function (navEntry) {
            // Respond to the incoming sort/page/filter parameters
            // by updating booksDataSource and re-querying the server
        }
    });
    

    接下来,您将使用可绑定到链接按钮等的命令定义一个或多个 Knockout.js 视图模型:

    var ViewModel = function (nav) {
      this.search = function () {
        nav.navigate({ page: 2, filter: '', ... }); // JSON object matching the NavHistory params
      };
    }
    

    最后,在您的标记中,您将使用 Knockout.js 将您的命令绑定到各种元素:

    <a data-bind="click: search">...</a>
    

    链接的资源更详细地解释了所有这些是如何工作的。不幸的是,它不是您正在寻找的单一框架,但您会惊讶地发现它是多么容易工作。

    还有一点,以 BigShelf 为例,我正在构建的网站完全跨浏览器兼容,IE6+、Firefox、Safari(移动和桌面)和 Chrome(移动和桌面)。

    【讨论】:

    【解决方案5】:

    AjaxTCR Library 似乎涵盖了所有基础并包含我以前从未见过的强大方法。它是根据 BSD 许可证(开源计划)发布的。

    例如,这里有五个 AjaxTCR.history(); 方法:

    init(onStateChangeCallback, initState);

    addToHistory(id, data, title, url, options);

    getAll();

    getPosition();

    enableBackGuard(消息,立即);

    上面的 addToHistory(); 有足够的参数来允许在网站中进行深度哈希链接。

    .com.cookie().storage().template() 的更多养眼提供了绰绰有余处理任何会话数据要求的方法。

    有据可查的AjaxTCR API webpage 有大量信息,可下载文档!

    状态更新:
    该网站还有一个 Examples Webpage Section,包括可下载的 .zip 文件,以及可以使用的前端客户端)和后端(服务器)项目文件。

    值得注意的是以下即用型示例:
    One-way Cookie
    HttpOnly Cookies
    History Stealing
    @ 987654327@

    还有很多其他示例完善了使用他们的许多 API 方法的过程,从而可以更快地完成任何小的学习曲线。

    【讨论】:

      【解决方案6】:

      几个建议

      注意:ExtJs History 一直是extended to optimize duplicate (redundant) calls to add()

      【讨论】:

      • 虽然 ExtJS 是一个很棒的框架,但它是 1) 如果仅用于所讨论的问题,那就太矫枉过正了; 2) 尚未实现新的 History API; 3)非常原始,没有路由框架+像你提到的那样的怪癖(关于冗余调用)
      【解决方案7】:

      PJAX 是您描述的过程。

      当用户将鼠标悬停在链接上时,更高级的 pjax 技术甚至会开始预加载内容。

      这是一个很好的 pjax 库。 https://github.com/MoOx/pjax

      您标记需要在后续请求中更新的容器:

      new Pjax({ selectors: ["title", ".my-Header", ".my-Content", ".my-Sidebar"] })
      

      所以在上面,只有title.my-header.my-content.my-sidebar 将被替换为来自 ajax 调用的内容。

      注意事项

      注意您的 JS 如何加载并检测页面何时准备就绪。 javascript 不会在新页面上重新加载。出于同样的原因,还要注意何时调用任何分析调用。

      【讨论】:

        猜你喜欢
        • 2011-07-31
        • 1970-01-01
        • 1970-01-01
        • 2010-12-21
        • 2014-03-13
        • 2013-08-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多