【问题标题】:pushState preventing Backbone.js routes from workingpushState 阻止 Backbone.js 路由工作
【发布时间】:2013-04-29 18:10:45
【问题描述】:

我在 RequireJS/Backbone.js 应用程序中遇到了 HTML5 pushState 问题,我很确定我做错了什么,但我无法确定问题所在,我已经尝试了几个小时。

前言:所有 RequireJS 依赖项都在其正确的文件夹中。

这是我的问题:我有一个基本的小设置 - 我使用的唯一 Backbone 组件是路由器。在默认的 '' 路由上,我在路由器中调用了一个 'home' 方法。这个方法只不过是提醒“Test”而已,它确实有效。

但是,一旦我将{pushState: true} 作为参数添加到顶级app.js 文件中的Backbone.history.start(),'home' 方法将不再被调用。

这些是发生这种情况的代码块:

index.html:

<!doctype html>
<html>
  <head>
    <title>Todo</title>
    <script data-main="assets/js/app/app.js" src="assets/js/app/lib/require.js"></script>
  </head>
  <body>
    <div id="main"></div>
  </body>
</html>

app.js:

require.config({
  baseUrl: 'assets/js/app',
  paths: {
    'underscore': 'lib/underscore',
    'jquery': 'lib/jquery',
    'backbone': 'lib/backbone',
    'text': 'lib/text',
    'handlebars': 'lib/handlebars',
    'router': 'router/router'
  },
  shim: {
    'underscore': {
      exports: '_'
    },
    'backbone': {
      deps: ['underscore', 'jquery'],
      exports: 'Backbone'
    }
  }
});
require(['router', 'backbone'], function(Router, Backbone) {
  var router = new Router();
  Backbone.history.start({ pushState: true });
});

router.js:

define(['backbone'], function(Backbone) {
  var Router = Backbone.Router.extend({
    routes: {
      '': 'home'
    },
    home: function() {
      alert('test');
    }
  });
  return Router;
});

我做错了什么?这是一种不正确、复杂的方法吗?

【问题讨论】:

    标签: javascript backbone.js pushstate


    【解决方案1】:

    我想出了一个解决我自己问题的方法,这很有趣。

    实现 pushState 的问题在于,要使任何路由正常工作,即使是默认主路由,也需要后端服务器来初始呈现页面,以便 Backbone 在检查路由后可以触发正确的 JavaScript。

    这意味着开发本地实例并使用file:// 协议导航到它将不起作用。 (这是我在上述问题中犯的错误)。

    对于这个简单的用例,我编写了一个简单的 ExpressJS 服务器,它在遇到 any 时提供 index.jade 视图(我删除了 index.html)wildcard 路由,然后允许 Backbone 使用这个微小的 sn-p 代码正确渲染路由:

    app.get('*', function(req, res) {
      res.render('index');
    }
    

    但是,如果您希望支持搜索引擎抓取,则势在必行进行进一步更改,并且这些更改涉及使您的服务器可以呈现的视图的特定于路由的服务器端版本如果直接访问路由。如果您不希望支持 SEO 可抓取性,例如在需要用户登录的 Web 应用程序的情况下,那么通过单个渲染文件重新路由 all 路由就可以了。 Backbone 足够智能,可以检测剩余的路由路径以呈现适当的视图。这是在the Backbone documentation

    请注意,使用真实 URL 需要您的 Web 服务器能够正确呈现这些页面,因此还需要进行后端更改。例如,如果您有 /documents/100 的路由,如果浏览器直接访问该 URL,则您的 Web 服务器必须能够提供该页面。对于完整的搜索引擎可抓取性,最好让服务器为页面生成完整的 HTML ......但如果它是一个 Web 应用程序,只需呈现与根 URL 相同的内容,然后用 Backbone 填充其余内容视图和 JavaScript 工作正常。

    注意: 使用 pushState 可能会对锚标签 (&lt;a href='/route'&gt;) 的工作方式产生影响,因为默认情况下,它们仍会尝试“刷新”页面以获取匹配的路由。 Backbone 的路由器提供了一个navigate 方法,当与单击事件处理程序结合使用时,您可以绕过此默认行为。 shioyama 发布了这样一个事件处理程序的示例,作为对 this question. 的回答

    完整代码改动:

    /app.js

    var
    express = require('express'),
    app = express();
    
    app.configure(function() {
      app.set('views', __dirname + '/views');
      app.set('view engine', 'jade');
      app.use(express.static(__dirname + '/assets'));
      app.use(app.router);
      app.locals.pretty = true;
    });
    
    app.get('*', function(req, res) {
      res.render('index');
    });
    
    app.listen(3030, function() {
      console.log("Listening on 3030");
    });
    

    /assets/js/app/app.js

    require.config({
      baseUrl: '/js/app',
      paths: {
        'underscore': 'lib/underscore',
        'jquery': 'lib/jquery',
        'backbone': 'lib/backbone',
        'text': 'lib/text',
        'handlebars': 'lib/handlebars',
        'router': 'router/router'
      },
      shim: {
        'underscore': {
          exports: '_'
        },
        'backbone': {
          deps: ['underscore', 'jquery'],
          exports: 'Backbone'
        }
      }
    });
    require(['router', 'backbone'], function(Router, Backbone) {
      var router = new Router();
      Backbone.history.start({pushState: true});
    });
    

    /assets/js/app/router/router.js

    define(['backbone', 'jquery'], function(Backbone, $) {
      var Router = Backbone.Router.extend({
        routes: {
          '': 'home',
          'fred': 'fred'
        },
        home: function() {
          $('#main').append('<p>This is the <strong>HOME</strong> route.');
        },
        fred: function() {
          $('#main').append('<p>This is the <strong>FRED</strong> route.');
        }
      });
      return Router;
    });
    

    /views/index.jade

    !!!
    html
      head
        title Todo
        script(data-main='/js/app/app.js', src='/js/app/lib/require.js')
      body
        #main
    

    【讨论】:

    • 我遇到了同样的问题,试图弄清楚为什么我的 Backbone 学习项目都能奏效,但卓别林的基本样板却没有。他们在构建路由器时选择 pushState: true 。弄清楚为什么那是可取的可能需要再花几个小时的阅读时间,但我真的很喜欢在没有任何服务器的情况下将所有文件放在 file:// url 上的简单性,尤其是当我的代码需要在 PhoneGap 之类的东西中可移植时
    • 还没有尝试过卓别林,但我相信你可以覆盖它,不是吗?
    • 是的,很容易完成,经过很长一段时间的代码尝试找出发生了什么。好吧,至少是一次很好的学习练习。
    猜你喜欢
    • 1970-01-01
    • 2013-01-07
    • 1970-01-01
    • 2012-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多