javascript - pushState 阻止 Backbone.js 路由工作

标签 javascript backbone.js pushstate

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

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

这是我的问题:我有一个基本的小设置 - 我使用的唯一主干组件是路由器。在默认的“”路由上,我在路由器中调用了一个“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>

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

我做错了什么?这是一种不正确的、令人费解的方法吗?

最佳答案

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

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

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

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

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

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

Note that using real URLs requires your web server to be able to correctly render those pages, so back-end changes are required as well. For example, if you have a route of /documents/100, your web server must be able to serve that page, if the browser visits that URL directly. For full search-engine crawlability, it's best to have the server generate the complete HTML for the page ... but if it's a web application, just rendering the same content you would have for the root URL, and filling in the rest with Backbone Views and JavaScript works fine.

注意: 使用 pushState 可能会影响 anchor 标记 ( <a href='/route'> ) 的工作方式,因为默认情况下,它们仍会尝试“刷新”页面以获取匹配的路由。 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

关于javascript - pushState 阻止 Backbone.js 路由工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16285401/

相关文章:

javascript - IE11 window.history.pushState "Object doesn' t 支持属性或方法 'pushState'

javascript - 数据克隆错误: The object could not be cloned

javascript - indexedDB openCursor 事务成功返回空数组

javascript - 创建模式,其字段之一包含引用另一个模式 objectId 的 objectId 和一个字符串

json - 将 Mongoose 模型引导到 BackboneJS

javascript - Backbone.js View 属性中的变量

javascript - ReactJS 可以渲染字符串吗?

javascript - 没有 ActiveX/Java 小程序的浏览器中的数字签名

javascript - Backbonejs 应用程序在导航到 `?state=#users` 时自动加载页面 `#users`

javascript - History.pushState 似乎会导致 gtag.js 再次加载(SPA)