Ember 中的路由

本文將介紹 **路由**,有時也稱為基於 URL 的過濾。我們將使用它為三個待辦事項檢視(“全部”、“活動”和“已完成”)提供唯一的 URL。

先決條件

至少,建議您熟悉核心 HTMLCSSJavaScript 語言,並瞭解 終端/命令列

對現代 JavaScript 特性(如類、模組等)的深入瞭解將非常有益,因為 Ember 大量使用它們。

目標 學習在 Ember 中實現路由。

基於 URL 的篩選

Ember 帶有一個與瀏覽器 URL 緊密整合的路由系統。通常,在編寫 Web 應用程式時,您希望頁面由 URL 表示,這樣如果(出於任何原因)頁面需要重新整理,使用者不會對 Web 應用程式的狀態感到意外——他們可以連結到應用程式的重要檢視。

目前,我們已經有“全部”頁面,因為我們目前沒有對我們一直使用的頁面進行任何過濾,但我們需要對其進行一些重組,以便處理“活動”和“已完成”待辦事項的不同檢視。

Ember 應用程式有一個預設的“application”路由,它與 app/templates/application.hbs 模板相關聯。因為該應用程式模板是我們待辦事項應用程式的入口點,所以我們需要進行一些更改以允許路由。

建立路由

讓我們從建立三個新的路由開始:“Index”、“Active”和“Completed”。為此,您需要在應用程式的根目錄中將以下命令輸入到您的終端中

bash
ember generate route index
ember generate route completed
ember generate route active

第二和第三個命令不僅應該生成了新檔案,而且還更新了一個現有檔案,app/router.js。它包含以下內容

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 檔案並替換

hbs
<TodoList />

hbs
{{outlet}}

接下來,在我們的 index.hbscompleted.hbsactive.hbs 模板中(也位於模板目錄中),我們現在可以只輸入 TodoList 元件呼叫。

在每種情況下,替換

hbs
{{outlet}}

hbs
<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。將以下內容新增到現有 getter 下面

js
get completed() {
  return this.todos.filter((todo) => todo.isCompleted);
}

模型

現在我們需要將模型新增到我們的路由 JavaScript 檔案中,以便我們可以輕鬆地返回特定資料集以在這些模型中顯示。model 是一個數據載入生命週期鉤子。對於 TodoMVC,模型的功能對我們來說並不那麼重要;如果您想深入瞭解,可以在 Ember 模型指南 中找到更多資訊。我們還提供了對服務的訪問,就像我們對元件所做的那樣。

索引路由模型

首先,更新 todomvc/app/routes/index.js 使其如下所示

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 以確保顯示所有待辦事項。

在此檔案中,更改

hbs
<TodoList />

hbs
<TodoList @todos={{ @model.allTodos }} />

已完成路由模型

現在更新 todomvc/app/routes/completed.js 使其如下所示

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 以確保僅顯示已完成的待辦事項。

在此檔案中,更改

hbs
<TodoList />

hbs
<TodoList @todos={{ @model.completedTodos }} />

活動路由模型

最後,對於路由,讓我們整理一下我們的活動路由。從更新 todomvc/app/routes/active.js 開始,使其如下所示

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 以確保僅顯示活動(未完成)的待辦事項。

在此檔案中,更改

hbs
<TodoList />

hbs
<TodoList @todos={{ @model.activeTodos }} />

請注意,在每個路由模型鉤子中,我們都返回一個帶有 getter 的物件,而不是一個靜態物件,或者更多地是靜態的待辦事項列表(例如,this.todos.completed)。這樣做是為了讓模板對待辦事項列表有一個動態引用,如果我們直接返回列表,資料將永遠不會重新計算,這將導致導航看起來像失敗/沒有實際過濾。透過在模型資料返回物件中定義一個 getter,待辦事項將被重新查詢,以便我們對待辦事項列表的更改會在渲染的列表中體現出來。

因此,我們的路由功能現在都已到位,但我們無法從應用程式中訪問它們。讓我們使頁尾連結處於活動狀態,以便單擊它們會轉到所需的路由。

回到 todomvc/app/components/footer.hbs,找到以下標記片段

hbs
<a href="#">All</a>
<a href="#">Active</a>
<a href="#">Completed</a>

更新為

hbs
<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 服務並迴圈遍歷所有待辦事項,如下所示

hbs
{{#each this.todos.all as |todo| }}

由於我們現在希望 TodoList 元件顯示一個過濾後的列表,因此我們希望向 TodoList 元件傳遞一個引數,該引數代表“當前待辦事項列表”,如下所示

hbs
{{#each @todos as |todo| }}

本教程到此結束!您的應用程式現在應該在頁尾中有完全有效的連結,顯示“Index”/預設、“Active”和“Completed”路由。

The todo list app, showing the routing working for all, active, and completed todos.

總結

恭喜!您已完成本教程!

在我們將此處介紹的內容與原始的 TodoMVC 應用程式 相比,還有很多東西要實現,例如編輯、刪除和跨頁面重新載入持久化待辦事項。

要檢視我們完成的 Ember 實現,請檢視本教程程式碼的儲存庫中完成的應用程式資料夾 此處,或檢視 即時部署版本。研究程式碼以瞭解有關 Ember 的更多資訊,並檢視下一篇文章,其中提供指向更多資源的連結以及一些故障排除建議。