3

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

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

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

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

这些是发生它的代码块:

索引.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>

应用程序.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 });
});

路由器.js:

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

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

4

1 回答 1

1

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

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

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

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

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

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

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

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

完整的代码更改:

/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
于 2013-04-30T22:22:14.503 回答