pushState阻止Backbone.js路由工作

时间:2013-04-29 18:10:46

标签: javascript backbone.js pushstate

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

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

这是我的问题:我有一个基本的小设置 - 我使用的唯一Backbone组件是路由器。在默认的''路线上,我在路由器中调用'home'方法。这种方法只是警告“测试”,它起作用。

但是,一旦我将{pushState: true}作为参数添加到顶级Backbone.history.start()文件中的app.js,就不再调用'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;
});

我做错了什么?这是一种错误的,错综复杂的方法吗?

1 个答案:

答案 0 :(得分:1)

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

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

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

对于这个简单的用例,我编写了一个简单的ExpressJS服务器,它在遇到任何 <时提供 index.jade 视图(我删除了index.html) strong>通配符路由,然后允许Backbone使用这一小段代码正确呈现路由:

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

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

中说明
  

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

注意:使用pushState可能会对锚标记(<a href='/route'>)的工作方式产生影响,因为默认情况下,它们仍会尝试“刷新”页面以获取匹配路线。 Backbone的路由器提供navigate方法,当与click事件处理程序结合使用时,允许您绕过此默认行为。 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