Ember 中的路由
在本文中,我們將學習路由,有時也稱作基於 URL 的過濾。我們將使用它為三個待辦事項檢視(“所有”、“活動”和“已完成”)提供一個唯一的 URL。
| 預備知識 |
至少,建議您熟悉核心 HTML、CSS 和 JavaScript 語言,並瞭解 終端/命令列。 Ember 大量使用現代 JavaScript 特性(如類、模組等),因此深入理解這些特性將非常有益。 |
|---|---|
| 目標 | 學習在 Ember 中實現路由。 |
基於 URL 的過濾
Ember 提供了一個與瀏覽器 URL 緊密整合的路由系統。通常,在編寫 Web 應用程式時,您希望頁面由 URL 表示,這樣如果(出於任何原因)頁面需要重新整理,使用者不會對 Web 應用程式的狀態感到驚訝 — 他們可以直接連結到應用程式的重要檢視。
目前,我們已經有了“所有”頁面,因為我們當前正在處理的頁面沒有進行任何過濾,但我們需要對其進行一些重組,以處理“活動”和“已完成”待辦事項的不同檢視。
Ember 應用程式有一個預設的“application”路由,它與 app/templates/application.hbs 模板關聯。由於該應用程式模板是我們待辦事項應用程式的入口點,我們需要進行一些更改以允許路由。
建立路由
讓我們從建立三個新路由開始:“Index”、“Active”和“Completed”。為此,您需要在應用程式的根目錄中,在終端中輸入以下命令
ember generate route index
ember generate route completed
ember generate route active
第二個和第三個命令不僅應該生成了新檔案,還更新了一個現有檔案 app/router.js。它包含以下內容
import EmberRouter from "@ember/routing/router";
import config from "./config/environment";
export default class Router extends EmberRouter {
location = config.locationType;
rootURL = config.rootURL;
}
Router.map(function () {
this.route("completed");
this.route("active");
});
高亮行是在執行上面第二個和第三個命令時新增的。
router.js 充當開發人員的“站點地圖”,以便能夠快速檢視整個應用程式的結構。它還告訴 Ember 如何與您的路由進行互動,例如在載入任意資料、處理載入資料時的錯誤或解釋 URL 的動態片段時。由於我們的資料是靜態的,我們不會接觸到那些高階功能,但我們仍然會確保路由提供檢視頁面所需的最少資料。
建立“Index”路由時沒有向 router.js 新增路由定義行,因為與 URL 導航和 JavaScript 模組載入一樣,“Index”是一個特殊詞,表示要渲染、載入等的預設路由。
為了調整我們舊的渲染 TodoList 應用程式的方式,我們首先需要將應用程式模板中的 TodoList 元件呼叫替換為 {{outlet}} 呼叫,這意味著“任何子路由都將在此處渲染”。
轉到 todomvc/app/templates/application.hbs 檔案,並將
<TodoList />
替換為
{{outlet}}
接下來,在我們的 index.hbs、completed.hbs 和 active.hbs 模板(也在模板目錄中)中,我們現在可以只輸入 TodoList 元件呼叫。
在每種情況下,替換
{{outlet}}
with
<TodoList />
因此,此時,如果您再次嘗試該應用程式並訪問這三個路由中的任何一個
localhost:4200 localhost:4200/active localhost:4200/completed
您將看到完全相同的內容。在每個 URL 中,與特定路徑(“Active”、“Completed”或“Index”)對應的模板將渲染 <TodoList /> 元件。頁面中 <TodoList /> 的渲染位置由父路由中的 {{ outlet }} 決定,在本例中是 application.hbs。所以我們的路由已經就位。太棒了!
但現在我們需要一種方法來區分這些路由,以便它們顯示它們應該顯示的內容。
首先,再次返回到我們的 todo-data.js 檔案。它已經包含一個返回所有待辦事項的 getter,以及一個返回未完成待辦事項的 getter。我們缺少的一個 getter 是返回已完成待辦事項的。在現有 getter 下方新增以下內容
export default class TodoDataService extends Service {
// …
get completed() {
return this.todos.filter((todo) => todo.isCompleted);
}
// …
}
模型
現在我們需要將模型新增到我們的路由 JavaScript 檔案中,以便我們可以輕鬆地返回特定的資料集以在這些模型中顯示。model 是一個數據載入生命週期鉤子。對於 TodoMVC,模型的功能對我們來說並不那麼重要;如果您想深入瞭解,可以在 Ember 模型指南 中找到更多資訊。我們還提供了對服務的訪問,就像我們對元件所做的那樣。
索引路由模型
首先,更新 todomvc/app/routes/index.js,使其看起來如下所示
import Route from "@ember/routing/route";
import { inject as service } from "@ember/service";
export default class IndexRoute extends Route {
@service("todo-data") todos;
model() {
let todos = this.todos;
return {
get allTodos() {
return todos.all;
},
};
}
}
我們現在可以更新 todomvc/app/templates/index.hbs 檔案,以便在它包含 <TodoList /> 元件時,它明確地使用可用模型,呼叫其 allTodos() getter,以確保顯示所有待辦事項。
在此檔案中,更改
<TodoList />
至
<TodoList @todos={{ @model.allTodos }} />
已完成路由模型
現在更新 todomvc/app/routes/completed.js,使其看起來如下所示
import Route from "@ember/routing/route";
import { inject as service } from "@ember/service";
export default class CompletedRoute extends Route {
@service("todo-data") todos;
model() {
let todos = this.todos;
return {
get completedTodos() {
return todos.completed;
},
};
}
}
我們現在可以更新 todomvc/app/templates/completed.hbs 檔案,以便在它包含 <TodoList /> 元件時,它明確地使用可用模型,呼叫其 completedTodos() getter,以確保只顯示已完成的待辦事項。
在此檔案中,更改
<TodoList />
至
<TodoList @todos={{ @model.completedTodos }} />
活動路由模型
最後對於路由,讓我們整理我們的活動路由。首先更新 todomvc/app/routes/active.js,使其看起來如下所示
import Route from "@ember/routing/route";
import { inject as service } from "@ember/service";
export default class ActiveRoute extends Route {
@service("todo-data") todos;
model() {
let todos = this.todos;
return {
get activeTodos() {
return todos.incomplete;
},
};
}
}
我們現在可以更新 todomvc/app/templates/active.hbs 檔案,以便在它包含 <TodoList /> 元件時,它明確地使用可用模型,呼叫其 activeTodos() getter,以確保只顯示活動的(未完成的)待辦事項。
在此檔案中,更改
<TodoList />
至
<TodoList @todos={{ @model.activeTodos }} />
請注意,在每個路由模型鉤子中,我們都返回一個帶有 getter 的物件,而不是一個靜態物件,或者僅僅是待辦事項的靜態列表(例如 this.todos.completed)。這樣做的原因是,我們希望模板對待辦事項列表有一個動態引用,如果我們直接返回列表,資料將永遠不會重新計算,這將導致導航看起來失敗/實際上沒有過濾。透過在模型資料的返回物件中定義一個 getter,待辦事項會重新查詢,以便我們對 todo 列表的更改反映在渲染列表中。
讓頁尾連結正常工作
所以我們的路由功能現在都已就位,但我們無法從我們的應用程式中訪問它們。讓我們啟用頁尾連結,以便點選它們可以轉到所需的路由。
回到 todomvc/app/components/footer.hbs,找到以下標記
<a href="#">All</a>
<a href="#">Active</a>
<a href="#">Completed</a>
將其更新為
<LinkTo @route="index">All</LinkTo>
<LinkTo @route="active">Active</LinkTo>
<LinkTo @route="completed">Completed</LinkTo>
<LinkTo> 是一個內建的 Ember 元件,它處理導航路由時的所有狀態更改,併為任何與 URL 匹配的連結設定一個“active”類,以防需要將其與非活動連結進行不同樣式設定。
更新 TodoList 中的待辦事項顯示
我們需要修復的最後一個小問題是,以前在 todomvc/app/components/todo-list.hbs 中,我們直接訪問 todo-data 服務並迴圈遍歷所有待辦事項,如下所示
{{#each this.todos.all as |todo| }}
由於我們現在希望 TodoList 元件顯示一個過濾列表,我們將需要向 TodoList 元件傳遞一個表示“當前待辦事項列表”的引數,如下所示
{{#each @todos as |todo| }}
本次教程到此結束!您的應用程式現在應該在頁尾中擁有完全可用的連結,可以顯示“Index”/預設、“Active”和“Completed”路由。

總結
恭喜!您已完成本教程!
在與原始 TodoMVC 應用程式 功能保持一致之前,我們還需要實現更多功能,例如編輯、刪除和在頁面重新載入時保留待辦事項。
要檢視我們完成的 Ember 實現,請檢視 本教程程式碼 倉庫中的已完成應用程式資料夾,或在此處檢視 即時部署版本。學習程式碼以瞭解更多關於 Ember 的資訊,並檢視下一篇文章,其中提供了更多資源連結和一些故障排除建議。