单页应用程序是那些运行在单个 HTML 文档上的应用程序。这意味着,如果您想向用户显示一些不同的内容,根据应用程序的状态,您将需要进行一些 DOM 操作(用不同的 HTML 剪切并替换当前文档的某些元素)以更新用户看到的“视图”。对不起,如果这对你来说是显而易见的,请不要生气。我想我应该从这里开始。请耐心等待,我将解释您的路由情况将如何发生(或多或少)。
URL 由几个不同的部分组成,每个部分都会通知浏览器下载用户尝试访问的资源所需的特定信息。通常,您要查找的资源位于某处的服务器上,并且浏览器知道这一点,因为 URL 中的“协议”(“http:”) 和“主机”(“www.mydomain.com”) 等部分,因此它会转到该服务器来查找您所请求的内容。 URL 中还有“查询”参数,它们向服务器提供一些有关特定操作的附加信息,例如搜索查询的搜索词。查询参数之后是“哈希”。哈希是单页应用程序的魔力发生的地方......呃,嗯,有点......
首先介绍一下哈希。当您向 URL 添加“#”时,浏览器会将其后面的信息解释为当前显示文档中的某个位置(元素)。这意味着,如果您有一个 'id' 为 'main' 的元素,并且将 '#main' 添加到 URL 末尾,如下所示: 'http://www.example.com#main',浏览器将将“滚动”(通常是“跳转”)到该元素的开头,以便您可以看到它。但请注意,如果您输入 'http://www.example.com/#main http://www.example.com/#main'(哈希值与 URL 之间用斜杠分隔),然后您将强制重新加载整个页面,浏览器将尝试在服务器上查找名为“#main”的文件(我打赌它找不到) 。
这里的要点是,如果 URL 中存在哈希值,浏览器将不会尝试离开当前文档,上面提到的情况当然是例外,这很好,因为单页应用程序不想离开该页面或从服务器请求新文档。 (看看单页应用程序的路由有何不同?)
现在,关于哈希的整个事情对于单页应用程序来说并不重要,因为您可以在不处理所有内容的情况下制作一个应用程序。您真正需要的只是一堆点击处理程序和 DOM 操作...但是,这意味着用户将无法共享指向应用程序中特定视图的链接。 URL 永远不会改变,我们永远无法直接导航到任何特定的视图。我们总是从应用程序的起始位置开始,这很容易成为一个非常烦人的情况。
如果您的单页应用程序将具有不同的视图,并且您希望用户能够通过书签或链接直接导航到特定的视图,那么除了您需要在后端实现的路由(数据 API 的路由等),这意味着您需要使用哈希。
我不想深入了解不同的框架如何在前端完成路由,但这基本上是在用户单击链接时更新浏览器的地址字段,并观察地址栏以确定当前 URL 是什么以及将与该 URL 关联的 HTML 加载到文档树中指定位置的 DOM 中。
因此,在单页应用程序中,服务器上有一个路由负责渲染应用程序 HTML 文档 (index.html),并且有负责处理应用程序数据的路由(在数据库、登录和注销、编辑或销毁数据库中的实例以及获取数据...),这些都是通过 AJAX 请求调用的。
这实际上是一个相当复杂的情况,因为 HTML5 允许我们能够放弃哈希(借助服务器上的一些链接重写),并且还能够使用“后退”和“前进”按钮,就像我们“实际上,我们已经离开了原始文档(我们没有这样做,因为我们只是将浏览器指向了完全相同的 URL,只是修改了哈希值,因此没有发生新页面加载)。传统的站点导航和链接可以通过利用浏览器的 History API 来实现,该 API 从版本 10 开始可用于 IE(我相信),其他大型浏览器供应商很早就已经开始使用它,因此利用框架这项技术将允许您的用户无需 URL 中的哈希值即可导航您的应用程序。解释这是一种消遣,对于理解单页应用程序中的路由来说不是必需的,但它很有趣,无论如何你最终都必须学习它,可能......
应使用 AJAX 从服务器请求 JSON。 AJAX 请求将始终到达您的服务器,因为您没有在 AJAX 请求中包含哈希符号(这样做会很荒谬,因为哈希仅用于文档内浏览),因此服务器端路由必须负责公开您的数据 API(考虑 RESTful 的 API)。虽然这不是它们在单页应用程序中的唯一目的,但这可能是它们最重要的目的。
Soooo,总而言之,您将有两组路线。一个在客户端(作为 AngularJS 或 EmberJS 等客户端框架的一部分,这样的例子不胜枚举……我更喜欢 Angular,但它的学习曲线相当陡峭。),另一个在服务器上。当您想到“服务器路由”时,请考虑数据 API。当您想到“页面路由”时,请记住,这一切都由您随初始服务器响应一起交付的 JavaScript 在客户端上处理(这是将 HTML 呈现到浏览器所涉及的唯一必要的服务器端路由,加载您的“index.html”以及所有必要的脚本和样式表等)。您将使用express.static中间件来提供静态文件,因此您不必担心为这些东西分配路由。
编辑 快速提及 AJAX 实现。
在服务器上,您将拥有与 Alex 作为示例提供的路由类似的路由,并且您将使用您选择的框架或库公开的任何 XMLHttpRequest (XHR) 对象从客户端调用这些 URL。现在,框架/库将这些请求作为承诺来实现或多或少被认为是标准和最佳实践http://wiki.commonjs.org/wiki/Promises/A http://wiki.commonjs.org/wiki/Promises/A。您应该自己阅读一些相关内容,但我也许可以通过说它是一个异步操作来总结它,类似于同步操作中的“try、catch、 throw”。您将实例化一个 Promise 对象,并通过它尝试从服务器加载数据,例如通过 GET 请求。确保您已分配函数来处理对您发出请求的 URL(服务器端路由)发出的请求!您实例化并随后通过该对象向服务器发出请求,承诺一旦从服务器返回请求的结果(无论是否成功),就会将请求的结果返回给您,如果成功,它将调用您编写的函数,将为它提供来自服务器的数据。如果失败,它将调用另一个由您编写的函数,并向其提供错误对象(或失败的“原因”),以便您可以适当地处理错误。
希望这有助于回答您的问题。