42

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

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

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

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

例如,在 Internet Explorer <10 和任何其他浏览器中单击Google+ 。

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

4

7 回答 7

21

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

  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)。

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

可访问性和所有这些 JavaScript 框架

于 2012-07-13T09:24:19.377 回答
9

我目前在我的一个应用程序中使用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 上测试)
  • 独立于所有第三方库,但与所有第三方库配合得很好

我发现最后一点最有吸引力。你可以在这里找到它们

希望这个对你有帮助。

于 2012-07-19T13:15:50.413 回答
8

我想建议一个组合

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'));
});​
于 2012-07-13T08:12:29.510 回答
5

你看过BigShelf 示例 SPA(单页应用程序)吗?听起来它涵盖了如何实现您所要求的大部分内容。

它利用 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(移动和桌面)。

于 2012-07-17T22:10:32.070 回答
3

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

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

初始化(onStateChangeCallback,initState);

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

得到所有();

获取位置();

enableBackGuard(消息,立即);

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

.com.cookie().storage().template()更吸引眼球的方法提供了足够多的方法来处理任何会话数据需求。

有据可查的AjaxTCR API 网页包含大量信息,可下载文档以供引导!

状态更新:
该网站还有一个示例网页部分,包括可下载的.zip 文件,其中包含可供使用的前端客户端)和后端服务器)项目文件。

值得注意的是以下即用型示例:
单向 Cookie
HttpOnly Cookies
History Stealing
History Explorer

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

于 2012-07-13T08:48:22.240 回答
3

几个建议

注意: ExtJs History 已扩展以优化对add().

于 2012-07-13T07:55:12.917 回答
1

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 不会在新页面上重新加载。出于同样的原因,还要注意何时调用任何分析调用。

于 2015-10-14T15:31:01.170 回答