本文章是由機器翻譯。

ASP.NET

單頁應用程式:透過 ASP.NET 建置新式、反應靈敏的 Web 應用程式

Mike Wasson

下载代码示例

單頁面應用程式 (Spa) 是單一的 HTML 頁面載入和動態地更新該頁面作為使用者交互的方式與應用程式的 Web 應用程式。

Spa 水療中心使用 AJAX 和 HTML5 創建流體和回應的 Web 應用程式,沒有恆定的頁面重新載入。然而,這意味著用戶端,在 JavaScript 中上發生了很多工作。對於傳統ASP.NET開發人員,它很難實現飛躍。幸運的是,有很多開源的 JavaScript 框架,使它更容易創建 spa 水療中心。

在本文中,我走過去創建一個簡單的 SPA 服務應用程式。一路走來,我將介紹一些基本概念建築 spa 水療中心,包括模型-視圖-控制器 (MVC) 和模型-視圖-ViewModel (MVVM) 模式、 資料繫結和路由。

关于示例应用程序

我創建的應用程式範例是一個簡單的影片資料庫,所示圖 1。頁面的左側欄顯示流派的清單。按一下一個流派的調出該風格電影的清單。按一下條目旁邊的編輯按鈕允許您更改該條目。完成編輯後,您可以按一下保存提交到伺服器,更新或取消要還原的更改。


圖 1 單頁面應用電影資料庫應用程式

我創建了兩個不同的版本,該應用程式的其中一個使用 Knockout.js 庫和其他使用 Ember.js 庫。這些兩個圖書館都有不同的方法,所以它是有教育意義,對它們進行比較。在這兩種情況下,用戶端應用程式是少於 150 條生產線的 JavaScript。在伺服器端,我用ASP.NETWeb API 為 JSON 向用戶端提供服務。您可以找到原始程式碼中的兩個版本在 app github.com/MikeWasson/MoviesSPA

(附註:我創建的應用程式使用的Visual Studio2013年發佈候選 [RC] 版本。有些事情可能改變為釋放生產 [RTM] 版本,但他們不應該影響代碼.)

背景資料

在傳統的 Web 應用程式中,每次應用程式調用伺服器,伺服器將呈現新的 HTML 頁。這會觸發瀏覽器中的刷新頁面。如果你寫過一個 Web 表單應用程式或 PHP 應用程式,此頁面生命週期應該非常熟悉。

在 SPA 後第一次的載入頁時,與該伺服器的所有交互都發生通過 AJAX 調用。這些 AJAX 調用返回的資料 — — 不標記 — — 通常以 JSON 格式。這款應用程式使用 JSON 資料不重新載入頁面的情況下動態地更新該頁面。圖 2 說明了這兩種方法之間的差異。


圖 2 傳統頁面生命週期 vs。水療中心生命週期

水療中心的一個好處是顯而易見的:應用程式都更加流暢的、 反應靈敏、 無刺耳重裝和重新呈現頁面的效果。另一個好處可能不那麼明顯,它有關你如何構建一個 Web 應用程式。將應用程式資料發送 JSON 作為創建演示文稿 (HTML 標籤) 和應用程式邏輯 (AJAX 請求加 JSON 回應) 之間的分隔。

這種分離使它容易設計與進化每個圖層。在構架良好的水療中心,您可以更改 HTML 標籤無接觸實現應用程式邏輯的代碼 (至少,那是最理想)。當我談到以後的資料繫結時您會看到這在行動中。

在純淨的溫泉,所有的使用者介面交互發生在用戶端,通過 JavaScript 和 CSS。後的初始頁面負載,伺服器行為純粹作為一個服務層。用戶端只需要知道要發送 HTTP 要求。它不在乎在後端伺服器如何實現的事情。

與這種體系結構,用戶端和服務是獨立的。您可以替換整個後端運行該服務,只要你不改變 API,你不會中斷用戶端。反過來也是如此 — — 你可以替換整個用戶端應用程式而無需更改服務層。例如,您可能會編寫一個使用服務的本機移動用戶端。

創建Visual Studio專案

Visual Studio2013年有單個ASP.NETWeb 應用程式專案類型。專案嚮導允許您選擇要包括在您的專案中的ASP.NET元件。我與空範本開始,然後添加到該專案ASP.NETWeb API 通過檢查 Web API 下"添加資料夾和核心的參考檔:"如中所示圖 3


圖 3 在Visual Studio2013年中創建一個新的ASP.NET專案

新的專案具有所需的 Web API,再加上一些 Web API 配置代碼的所有庫。我沒拿任何 Web 表單或ASP.NETMVC 的依賴。

注意在圖 3 Visual Studio2013年包含單個頁面應用程式範本。此範本安裝骨架溫泉建在 Knockout.js 上。它支援日誌中使用成員資格資料庫或外部身份檢查器提供者。我沒有在我的應用程式中用範本,因為我想要顯示一個簡單的例子,從零開始。SPA 範本是一個極大的資源,雖然,特別是如果你想要添加到您的應用程式的身份驗證。

創建服務層

我用ASP.NETWeb API 來創建簡單的其餘部分 API 的應用程式。我不會去詳細地討論 Web API 在這裡 — — 你可以閱讀更多在 asp.net/web-api。

第一,我創建了一個電影類,表示一部電影。此類有兩個作用:

  • Entity Framework(EF) 講述如何創建要存儲的電影資料的資料庫表。
  • 告訴 Web API 如何設置格式 JSON 負載。

你不必為兩者都使用相同的模型。例如,您可能希望您的資料庫架構,看起來不同于你的 JSON 有效載荷。這個 app,我保持事情簡單:

namespace MoviesSPA.Models
{
  public class Movie
  {
    public int ID { get; set; }
    public string Title { get; set; }
    public int Year { get; set; }
    public string Genre { get; set; }
    public string Rating { get; set; }
  }
}

下一步,我用Visual Studio腳手架來創建一個 Web API 控制器,使用 EF 作為資料層。使用基架,用滑鼠右鍵按一下解決方案資源管理器中的控制器資料夾並選擇添加 |基架的新項。在添加腳手架嚮導中,選擇"Web API 2 控制器的操作,使用Entity Framework,"中所示圖 4


圖 4 添加 Web API 控制器

圖 5 顯示添加控制器嚮導。我的名字 MoviesController 控制器。名稱很重要,因為其餘 API 為 Uri 基於控制器的名稱。我還檢查"使用非同步控制器操作"在 EF 6 採取新的非同步功能的優點。我所選擇的模型和所選的"新資料上下文"的電影類來創建一個新的 EF 資料上下文。


圖 5 添加控制器嚮導

嚮導添加兩個檔:

  • MoviesController.cs 定義的 Web API 控制器的實現用於應用程式的其餘部分 API。
  • MovieSPACoNtext.cs 基本上是 EF 膠,提供基礎資料庫中查詢的方法。

圖 6 顯示缺省的其餘部分 API 腳手架創建。

圖 6 預設其餘 API 創建的 Web API 腳手架

HTTP 動詞命令 URI 描述
GET / api/電影 獲取所有電影的清單
GET /api/電影 / {id} 獲得電影與 ID 等於 {id}
PUT /api/電影 / {id} 更新的電影 ID 等於 {id}
POST / api/電影 向資料庫中添加一部新電影
DELETE /api/電影 / {id} 從資料庫中刪除一部電影

大括弧中的值的預留位置。例如,若要獲取的電影的 ID 等於 5,URI 是 /api/movies/5。

我通過添加一個方法,在一個指定的流派中查找所有電影擴展此 API:

public class MoviesController : ApiController
{
  public IQueryable<Movie> GetMoviesByGenre(string genre)
  {
    return db.Movies.Where(m =>
      m.Genre.Equals(genre, StringComparison.OrdinalIgnoreCase));
  }
  // Other code not shown

用戶端將體裁放在 URI 的查詢字串。 例如,要獲取所有電影戲劇流派中,用戶端發送一個都 GET 請求/api/電影? 流派 = 戲劇。 Web API 會自動綁定到類型參數在 GetMoviesByGenre 方法中的查詢參數。

創建 Web 用戶端

到目前為止,我剛剛創建了一種休息的 API。 如果您發送一個 GET 請求/api/電影? 流派 = 戲劇,原始的 HTTP 回應看起來是這樣:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Date: Tue, 10 Sep 2013 15:20:59 GMT
Content-Length: 240
[{"ID":5,"Title":"Forgotten Doors","Year":2009,"Genre":"Drama","Rating":"R"}, {"ID":6,"Title":"Blue Moon June","Year":1998,"Genre":"Drama","Rating":"PG-13"},{"ID":7,"Title":"The Edge of the Sun","Year":1977,"Genre":"Drama","Rating":"PG-13"}]

現在我需要寫一個用戶端應用程式,不會用這個有意義的東西。 基本工作流程是:

  • UI 觸發 AJAX 請求
  • 更新顯示回應有效載荷的 HTML
  • 處理 AJAX 錯誤

你可以用手通過編寫代碼所有這一切。 例如,下面是一些 jQuery 代碼,創建一個電影標題的清單:

$.getJSON(url)
  .done(function (data) {
    // On success, "data" contains a list of movies
    var ul = $("<ul></ul>")
    $.each(data, function (key, item) {
      // Add a list item
      $('<li>', { text: item.Title }).appendTo(ul);
    });
  $('#movies').html(ul);
});

這段代碼有幾個問題。它混合應用程式邏輯與演示文稿的邏輯,並且它緊緊地綁定到你的 HTML。並且,它是很繁瑣的事寫。而不是聚焦于你的應用程式,你花時間寫事件處理常式和代碼來操作 dom。

解決方案是一個 JavaScript 框架之上再建。運氣­師長,你可以選擇從許多開放源碼 JavaScript 框架。一些較受歡迎的包括骨幹、 角、 餘燼、 挖空、 道場和 JavaScriptMVC。大多數使用一些變異的 MVC 或使用 MVVM 模式,所以有可能審查這些模式很有説明。

MVC 和使用 MVVM 模式

MVC 模式日期回到上世紀 80 年代和早期的圖形化使用者介面。MVC 的目標是將代碼分解為三個單獨的責任,所示圖 7。這裡是他們做什麼:

  • 模型表示的域的資料和業務邏輯。
  • 視圖顯示的模型。
  • 控制器接收使用者輸入,並將更新模型。


圖 7 MVC 模式

更多最近的 MVC 變形是 MVVM 模式 (請參閱圖 8)。在使用 MVVM:

  • 模型仍然表示域的資料。
  • 視圖模型是對視圖的抽象表示。
  • 該視圖顯示的視圖模型,併發送查看模型的使用者輸入。


圖 8 使用 MVVM 模式

在 JavaScript MVVM 框架內,該視圖是標記和視圖模型是代碼。

MVC 有許多變形,MVC 的文獻往往是令人困惑和矛盾。或許這並不奇怪的家常話 76 的入門和仍在現代的 Web 應用程式中正在使用的設計模式。所以雖然它是很好,知道理論,最主要的是要瞭解你正在使用的特定 MVC 框架。

建築與 Knockout.js 的 Web 用戶端

我的應用程式的第一個版本,我用的 Knockout.js 庫。挖空遵循使用 MVVM 模式,使用資料繫結來連接視圖與視圖模型。

若要創建資料繫結,您對 HTML 元素添加特殊的資料繫結屬性。例如,下面的標記將 span 元素繫結到一個名為體裁的視圖模型屬性。只要流派的值發生更改,挖空自動更新 HTML:

  <h1><span data-bind="text: genre"></span></h1>

綁定也可以工作在另一個方向 — — 例如,如果使用者輸入到文字方塊中的文本,挖空更新視圖模型中的相應屬性。

好的部分是資料繫結是聲明性語言。 你不用到電線,再到 HTML 頁面元素的視圖模式。 只需添加的資料繫結屬性和挖空不會休息。

我一開始沒有資料繫結,與具有基本的佈局,創建一個 HTML 頁中所示圖 9

(附註:引導庫用於樣式的應用程式,所以真正的應用程式有很多的額外 < div > 元素和控制格式的 CSS 類。 離開這些從清晰的代碼示例)

圖 9 初始 HTML 佈局

<!DOCTYPE html>
<html>
<head>
  <title>Movies SPA</title>
</head>
<body>
  <ul>
    <li><a href="#"><!-- Genre --></a></li>
  </ul>
  <table>
    <thead>
      <tr><th>Title</th><th>Year</th><th>Rating</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><!-- Title --></td>
        <td><!-- Year --></td>
        <td><!-- Rating --></td></tr>
    </tbody>
  </table>
  <p><!-- Error message --></p>
  <p>No records found.</p>
</body>
</html>

創建視圖模型

可觀測物件是挖空的資料繫結體系的核心。 可測的是存儲值的物件,可以在值發生更改時通知訂閱伺服器。 下面的代碼將一部電影的 JSON 表示形式轉換成具有可觀測物件的等效物件:

function movie(data) {
  var self = this;
  data = data || {};
  // Data from model
  self.ID = data.ID;
  self.Title = ko.observable(data.Title);
  self.Year = ko.observable(data.Year);
  self.Rating = ko.observable(data.Rating);
  self.Genre = ko.observable(data.Genre);
};

圖 10 演示我的視圖模型的初始實現。 此版本僅支援獲取的電影清單。 我會在以後添加編輯功能。 視圖模型包含的可觀測物件有關的電影、 一個錯誤字串和當前類型排列的主題清單。

圖 10 視圖模型

var ViewModel = function () {           
  var self = this;
  // View model observables
  self.movies = ko.observableArray();
  self.error = ko.observable();
  self.genre = ko.observable();  // Genre the user is currently browsing
  // Available genres
  self.genres = ['Action', 'Drama', 'Fantasy', 'Horror', 'Romantic Comedy'];
  // Adds a JSON array of movies to the view model
  function addMovies(data) {
    var mapped = ko.utils.arrayMap(data, function (item) {
      return new movie(item);
    });
    self.movies(mapped);
  }
  // Callback for error responses from the server
  function onError(error) {
    self.error('Error: ' + error.status + ' ' + error.statusText);
  }
  // Fetches a list of movies by genre and updates the view model
  self.getByGenre = function (genre) {
    self.error(''); // Clear the error
    self.genre(genre);
    app.service.byGenre(genre).then(addMovies, onError);
  };
  // Initialize the app by getting the first genre
  self.getByGenre(self.genres[0]);
}
// Create the view model instance and pass it to Knockout
ko.applyBindings(new ViewModel());

請注意電影是 observableArray。 顧名思義,observableArray 作為一個陣列,陣列內容一更改時通知訂閱者。

GetByGenre 函數使得 AJAX 請求到伺服器的電影清單,然後填充 self.movies 陣列的結果。

當你消費了其餘的 API 時,最棘手的部分之一處理 HTTP 的非同步特性。 JQuery ajax 函數返回實現諾言 API 的物件。 你可以使用一個承諾物件然後方法設置當 AJAX 調用成功完成時調用的回檔和另一個 AJAX 調用失敗時調用的回檔:

app.service.byGenre(genre).then(addMovies, onError);

資料繫結

現在,我有一個視圖模型,資料繫結 HTML 到它能 出現在螢幕的左側的流派清單,我用以下資料繫結:

<ul data-bind="foreach: genres">
  <li><a href="#"><span data-bind="text: $data"></span></a></li>
</ul>

資料繫結屬性包含一個或多個具有約束力的聲明,其中每個綁定具有表單"綁定:運算式"。在此示例中,foreach 綁定告訴挖空來迴圈遍歷視圖模型中的流派陣列的內容。 對於陣列中的每個項,挖空將創建一新的 < 李 > 元素。 在 < 跨度 > 文本綁定 設置的跨度文本等於陣列項,在這種情況下是流派的名稱的值。

權利現在,點擊體裁名稱不會做任何事,因此增加了點擊綁定以處理按一下事件:

<li><a href="#" data-bind="click: $parent.getByGenre">
  <span data-bind="text: $data"></span></a></li>

這將在按一下事件綁定到視圖模型上的 getByGenre 函數。 我需要在這裡,使用 $parent,因為此綁定發生 foreach 的範圍內。 預設情況下,在 foreach 內的綁定是指在迴圈中的當前項。

若要顯示的電影清單,添加綁定到表中,如中所示圖 11

圖 11 添加綁定到表以顯示的電影清單

<table data-bind="visible: movies().length > 0">
  <thead>
    <tr><th>Title</th><th>Year</th><th>Rating</th><th></th></tr>
  </thead>
  <tbody data-bind="foreach: movies">
    <tr>
      <td><span data-bind="text: Title"></span></td>
      <td><span data-bind="text: Year"></span></td>
      <td><span data-bind="text: Rating"></span></td>
      <td><!-- Edit button will go here --></td>
    </tr>
  </tbody>
</table>

圖 11、 foreach 約束力迴圈結束電影物件的陣列。 在 foreach 內, 文本綁定引用當前物件的屬性。

< 表 > 上可見綁定 元素控制是否呈現表。 如果電影陣列為空,這將隱藏表。

最後,在這裡的綁定的錯誤訊息和"找不到記錄"消息 (請注意您可以將複雜的運算式,變成一個具有約束力):

<p data-bind="visible: error, text: error"></p>
<p data-bind="visible: !error() && movies().length == 0">No records found.</p>

使記錄可編輯

這個應用程式的最後一部分使使用者能夠編輯表中的記錄。 這涉及到幾位的功能:

  • 查看模式 (純文字) 和編輯模式 (輸入控制項) 之間切換。
  • 提交到伺服器的更新。
  • 讓使用者取消編輯並恢復到原始資料。

若要跟蹤查看/編輯模式,添加一個布林值的旗幟在影片物件,作為一個可觀測物件:

function movie(data) {
  // Other properties not shown
  self.editing = ko.observable(false);
};

我想要電影時要顯示文本的編輯屬性為 false,但切換到輸入控制項進行編輯時是事實的表。 要做到這一點,我用挖空如果和 ifnot 綁定,如中所示圖 12。 "<! — — Ko-->"語法允許您包括如果和 ifnot 綁定而不把它們放在 HTML 容器元素內。

圖 12 啟用編輯的電影記錄

<tr>
  <!-- ko if: editing -->
  <td><input data-bind="value: Title" /></td>
  <td><input type="number" class="input-small" data-bind="value: Year" /></td>
  <td><select class="input-small"
    data-bind="options: $parent.ratings, value: Rating"></select></td>
  <td>
    <button class="btn" data-bind="click: $parent.save">Save</button>
    <button class="btn" data-bind="click: $parent.cancel">Cancel</button>
  </td>
  <!-- /ko -->
  <!-- ko ifnot: editing -->
  <td><span data-bind="text: Title"></span></td>
  <td><span data-bind="text: Year"></span></td>
  <td><span data-bind="text: Rating"></span></td>
  <td><button class="btn" data-bind="click: $parent.edit">Edit</button></td>
  <!-- /ko -->
</tr>

值綁定設置的輸入控制項的值。 這是一個雙向的約束力,因此當使用者在文字欄位中鍵入的東西或更改下拉清單選擇,此更改會自動傳播到視圖模型。

我按鈕按一下事件處理常式綁定到函數命名保存、 取消和編輯檢視模型上。

編輯功能是很容易的。 只是將編輯標誌設置為 true:

self.edit = function (item) {
  item.editing(true);
};

保存和取消了有點棘手。 為了支援取消,我需要一種方法在編輯過程中緩存的原始值。 幸運的是,挖空容易地擴展可觀測物件的行為。 中的代碼圖 13 將一個存儲函數添加到可觀察到的類。 上一個可觀測物件調用存儲函數給出的可觀察到的兩個新功能:還原和承諾。

圖 13 擴展 ko.observable 與還原和提交

現在我可以調用存儲函數將此功能添加到模型:

function movie(data) {
  // ...
// New code:
  self.Title = ko.observable(data.Title).store();
  self.Year = ko.observable(data.Year).store();
  self.Rating = ko.observable(data.Rating).store();
  self.Genre = ko.observable(data.Genre).store();
};

圖 14 顯示保存和取消上視圖模型的功能。

圖 14 添加保存和取消功能

self.cancel = function (item) {
  revertChanges(item);
  item.editing(false);
};
self.save = function (item) {
  app.service.update(item).then(
    function () {
      commitChanges(item);
    },
    function (error) {
      onError(error);
      revertChanges(item);
    }).always(function () {
      item.editing(false);
  });
}
function commitChanges(item) {
  for (var prop in item) {
    if (item.hasOwnProperty(prop) && item[prop].commit) {
      item[prop].commit();
    }
  }
}
function revertChanges(item) {
  for (var prop in item) {
    if (item.hasOwnProperty(prop) && item[prop].revert) {
      item[prop].revert();
    }
  }
}

建築與餘燼 Web 用戶端

為比較,我寫了另一個版本的我使用 Ember.js 庫的應用程式。

餘燼 app 啟動與路由表中,它定義了使用者將如何導航通過這款應用程式:

window.App = Ember.Application.create();
App.Router.map(function () {
  this.route('about');
  this.resource('genres', function () {
    this.route('movies', { path: '/:genre_name' });
  });
});

第一行代碼創建餘燼的應用程式。 對 Router.map 的調用創建三條路線。 URI 或 URI 對應每個路由模式:

/#/about
/#/genres
/#/genres/genre_name

每一條路線,您創建的 HTML 範本使用把手模板庫。

餘燼有整個應用程式的頂級範本。 此範本會為每個路由獲取呈現。 圖 15 顯示我的應用程式的應用程式範本。 正如您所看到的該範本基本上是 HTML,放置在具有類型的腳本標記內 ="x/文本-把手"該範本包含特殊把手標記內雙大括弧:{{ }}. 此標記將類似目的作為中挖空的資料繫結屬性。 例如,{{#linkTo}} 創建一個連結到工藝路線。

圖 15 中的應用水準把手模板

ko.observable.fn.store = function () {
  var self = this;
  var oldValue = self();
  var observable = ko.computed({
    read: function () {
      return self();
    },
    write: function (value) {
      oldValue = self();
      self(value);
    }
  });
  this.revert = function () {
    self(oldValue);
  }
  this.commit = function () {
    oldValue = self();
  }
  return this;
}
<script type="text/x-handlebars" data-template-name="application">
  <div class="container">
    <div class="page-header">
      <h1>Movies</h1>
    </div>
    <div class="well">
      <div class="navbar navbar-static-top">
        <div class="navbar-inner">
          <ul class="nav nav-tabs">
            <li>{{#linkTo 'genres'}}Genres{{/linkTo}} </li>
            <li>{{#linkTo 'about'}}About{{/linkTo}} </li>
          </ul>
        </div>
      </div>
    </div>
    <div class="container">
      <div class="row">{{outlet}}</div>
    </div>
  </div>
  <div class="container"><p>&copy;2013 Mike Wasson</p></div>
</script>

現在假設使用者導航到 / #/ 有關。 這將調用"關於"路線。 餘燼首先呈現頂級應用程式的範本。 然後它將呈現有關範本裡面的 {{}} 的出口該應用程式範本。 這裡是關於範本:

<script type="text/x-handlebars" data-template-name="about">
  <h2>Movies App</h2>
  <h3>About this app...</h3>
</script>

圖 16 顯示如何有關範本內的應用程式範本呈現。


圖 16 呈現有關範本

因為每條路線都有它自己的 URI,瀏覽器歷史記錄保存。使用者可以使用後退按鈕導航。使用者還可以刷新頁面,而不會丟失,或書簽並重新載入同一頁。

餘燼控制器和模型

在餘燼,每條路線有模型和控制器。該模型包含的域資料。控制器充當代理的模型,並將存儲任何應用程式狀態資料的視圖。(這不會完全符合 MVC 的經典的定義。在某些方面,該控制器更像是一個視圖模型。)

這裡是如何定義的電影模型:

App.Movie = DS.Model.extend({
  Title: DS.attr(),
  Genre: DS.attr(),
  Year: DS.attr(),
  Rating: DS.attr(),
});

控制器是來自 Ember.ObjectController,如中所示圖 17

圖 17 電影控制器從 Ember.ObjectController 派生

App.MovieController = Ember.ObjectController.extend({
  isEditing: false,
  actions: {
    edit: function () {
      this.set('isEditing', true);
    },
    save: function () {
      this.content.save();
      this.set('isEditing', false);
    },
    cancel: function () {
      this.set('isEditing', false);
      this.content.rollback();
    }
  }
});

有一些有趣的事情發生在這裡。 第一,我沒有在控制器類中指定的模型。 預設情況下,路由自動設置模型的控制器上。 第二,保存和取消功能使用內置 DS 的交易功能。模型的類。 要還原的編輯,只是在模型上調用回滾功能。

餘燼使用大量的命名約定來連接不同的元件。 流派路由會談到 GenresController,呈現流派的範本。 事實上,餘燼將自動創建一個 GenresController 物件,如果你不定義一個。 但是,您可以重寫預設設置。

在我的應用程式,我配置要使用不同的控制器通過實施 renderTemplate 鉤的流派/電影路由。 這種方式,幾條路線可以共用相同的控制器 (請參見圖 18)。

圖 18 幾條路線可以共用相同的控制器

App.GenresMoviesRoute = Ember.Route.extend({
  serialize: function (model) {
    return { genre_name: model.get('name') };
  },
  renderTemplate: function () {
    this.render({ controller: 'movies' });
  },
  afterModel: function (genre) {
    var controller = this.controllerFor('movies');
    var store = controller.store;
    return store.findQuery('movie', { genre: genre.get('name') })
    .then(function (data) {
      controller.set('model', data);
  });
  }
});

微光城市的一大優點就是你可以用很少的代碼做。 我的應用程式範例是約 110 行的 JavaScript。 這是比挖空的版本,較短,為免費瀏覽器歷史記錄。 另一方面,餘燼也是一個高度"自以為是"的框架。 如果你不寫您的代碼的"餘燼方法",你可能要打一些路障。 當選擇一個框架,您應該考慮的功能集和框架的整體設計是否匹配您的需要和編碼風格。

了解更多資訊

在本文中,我表明如何 JavaScript 框架使它更易於創建 spa 水療中心。 一路走來,我介紹了這些庫,包括資料繫結、 路由和 MVC 和使用 MVVM 模式的一些共同特徵。 你可以瞭解更多關於建築與ASP.NET在 spa 水療中心 asp.net 頁/單個應用程式

Mike Wasson 是一個在微軟的程式師作家。許多年來他記錄了 Win32 的多媒體 Api。他目前正在寫關於ASP.NET,側重于 Web API。您可以與他在聯繫 mwasson@microsoft.com

衷心感谢以下技术专家对本文的审阅:Xinyang Qiu (Microsoft)
Xinyang Qiu是 MicrosoftASP.NET團隊和活躍的博主為測試高級軟體設計工程師 blogs.msdn.com/b/webdev。 他很樂意回答ASP.NET問題或直接的專家來回答您的問題。 聯繫到他在 xinqiu@microsoft.com