頁面、路由和版面配置

提示

本內容節錄自《Blazor for ASP NET Web Forms Developers for Azure》電子書,可以從 .NET Docs 取得,也可以免費下載 PDF 離線閱讀。

Blazor-for-ASP-NET-Web-Forms-Developers eBook cover thumbnail.

ASP.NET Web Forms 應用程式是由 .aspx 檔案中定義的頁面所組成。 每個頁面的位址都是以其在專案中的實體檔案路徑為基礎。 當瀏覽器對頁面提出要求時,會在伺服器上動態轉譯頁面的內容。 該轉譯會同時處理頁面的 HTML 標記和其伺服器控制項。

在 Blazor 中,應用程式中的每個頁面都是一個元件,通常會定義於 .razor 檔案中,且具有一或多個指定的路由。 路由傳送大部分發生於用戶端,而不會涉及特定的伺服器要求。 瀏覽器會先對應用程式的根位址提出要求。 然後,Blazor 應用程式中的根 Router 元件會負責攔截瀏覽要求,並將其轉接至正確的元件。

Blazor 也支援「深層連結」。 當瀏覽器對應用程式的根以外的特定路由提出要求時,就會發生深層連結。 傳送至伺服器的深層連結要求會路由傳送至 Blazor 應用程式,然後將要求用戶端路由傳送至正確的元件。

ASP.NET Web Forms 中的簡單頁面可能包含下列標記:

Name.aspx

<%@ Page Title="Name" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Name.aspx.cs" Inherits="WebApplication1.Name" %>

<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
    <div>
        What is your name?<br />
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        <asp:Button ID="Button1" runat="server" Text="Submit" OnClick="Button1_Click" />
    </div>
    <div>
        <asp:Literal ID="Literal1" runat="server" />
    </div>
</asp:Content>

Name.aspx.cs

public partial class Name : System.Web.UI.Page
{
    protected void Button1_Click1(object sender, EventArgs e)
    {
        Literal1.Text = "Hello " + TextBox1.Text;
    }
}

Blazor 應用程式中的對等頁面看起來如下:

Name.razor

@page "/Name"
@layout MainLayout

<div>
    What is your name?<br />
    <input @bind="text" />
    <button @onclick="OnClick">Submit</button>
</div>
<div>
    @if (name != null)
    {
        @:Hello @name
    }
</div>

@code {
    string text;
    string name;

    void OnClick() {
        name = text;
    }
}

建立頁面

若要在 Blazor 中建立頁面,請建立元件,並新增 @page Razor 指示詞來指定元件的路由。 @page 指示詞會採用單一參數,這是要新增至該元件的路由範本。

@page "/counter"

路由範本參數是必要的。 不同於 ASP.NET Web Forms,對 Blazor 元件的路由「無法」從其檔案位置加以推斷 (雖然那可能是未來要新增的功能)。

路由範本語法與在 ASP.NET Web Forms 中用來進行路由傳送的基本語法相同。 路由參數需使用大括弧在範本中指定。 Blazor 會將路由值繫結至具有相同名稱的元件參數 (不區分大小寫)。

@page "/product/{id}"

<h1>Product @Id</h1>

@code {
    [Parameter]
    public string Id { get; set; }
}

您也可以指定路由參數值的限制式。 例如,若要將產品識別碼限制為 int

@page "/product/{id:int}"

<h1>Product @Id</h1>

@code {
    [Parameter]
    public int Id { get; set; }
}

如需 Blazor 所支援之路由限制式的完整清單,請參閱路由限制式

路由器元件

Blazor 中的路由傳送會由 Router 元件處理。 Router 元件通常用於應用程式的根元件 (App.razor) 中。

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <LayoutView Layout="@typeof(MainLayout)">
            <p>Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

Router 元件會在指定的 AppAssembly 和選擇性指定的 AdditionalAssemblies 中探索可路由的元件。 當瀏覽器瀏覽時,Router 會攔截瀏覽,並在路由符合位址時,使用擷取的 RouteData 來轉譯其 Found 參數的內容,否則,Router 會轉譯其 NotFound 參數。

RouteView 元件會處理轉譯 RouteData 所指定的相符元件及其配置 (如果有的話)。 如果相符的元件沒有配置,則會使用選擇性指定的 DefaultLayout

LayoutView 元件會在指定的配置內轉譯其子內容。 我們將在此章節稍後更詳細地查看配置。

在 ASP.NET Web Forms 中,您會將重新導向回應傳回至瀏覽器,以觸發瀏覽至不同頁面。 例如:

protected void NavigateButton_Click(object sender, EventArgs e)
{
    Response.Redirect("Counter");
}

通常無法在 Blazor 中傳回重新導向回應。 Blazor 不會使用要求-回覆模型。 不過,您可以直接觸發瀏覽器瀏覽,就像您使用 JavaScript 一樣。

Blazor 提供 NavigationManager 服務,可用來:

  • 取得目前的瀏覽器位址
  • 取得基底位址
  • 觸發瀏覽
  • 在位址變更時收到通知

若要瀏覽至不同的位址,請使用 NavigateTo 方法:

@page "/"
@inject NavigationManager NavigationManager

<button @onclick="Navigate">Navigate</button>

@code {
    void Navigate() {
        NavigationManager.NavigateTo("counter");
    }
}

如需所有 NavigationManager 成員的描述,請參閱 URI 和瀏覽狀態協助程式

基底 URL

如果您的 Blazor 應用程式部署於基底路徑之下,則您必須使用 <base> 標記,在頁面中繼資料內指定基底 URL,以便路由傳送至工作屬性。 如果使用 Razor 對應用程式的主機頁面進行伺服器轉譯,則您可以使用 ~/ 語法來指定應用程式的基底位址。 如果主機頁面是靜態 HTML,則您必須明確指定基底 URL。

<base href="~/" />

頁面版面配置

ASP.NET Web Forms 中的頁面配置會由主版頁面處理。 主版頁面會定義含有一或多個內容預留位置的範本,其接著可由個別頁面提供內容。 主版頁面定義於 .master 檔案中,並以 <%@ Master %> 指示詞開頭。 .master 檔案內容的編碼方式與 .aspx 頁面相同,但新增了 <asp:ContentPlaceHolder> 控制項來標記頁面可以提供內容的位置。

Site.master

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="WebApplication1.SiteMaster" %>

<!DOCTYPE html>
<html lang="en">
<head runat="server">
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title><%: Page.Title %> - My ASP.NET Application</title>
    <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
</head>
<body>
    <form runat="server">
        <div class="container body-content">
            <asp:ContentPlaceHolder ID="MainContent" runat="server">
            </asp:ContentPlaceHolder>
            <hr />
            <footer>
                <p>&copy; <%: DateTime.Now.Year %> - My ASP.NET Application</p>
            </footer>
        </div>
    </form>
</body>
</html>

在 Blazor 中,您使用配置元件來處理頁面配置。 配置元件繼承自 LayoutComponentBase,其會定義 RenderFragment 類型的單一 Body 屬性,可用來轉譯頁面的內容。

MainLayout.razor

@inherits LayoutComponentBase
<h1>Main layout</h1>
<div>
    @Body
</div>

在轉譯具有配置的頁面時,該頁面會在指定配置轉譯其 Body 屬性的位置上,於配置的內容中進行轉譯。

若要將配置套用至頁面,請使用 @layout 指示詞:

@layout MainLayout

您可以使用 _Imports.razor 檔案,來指定資料夾及子資料夾中所有元件的配置。 您也可以使用路由器元件,來指定所有頁面的預設配置。

主版頁面可以定義多個內容預留位置,但 Blazor 中的配置只有單一 Body 屬性。 這個對於 Blazor 配置元件的限制可望在未來版本中獲得解決。

ASP.NET Web Forms 中的主版頁面可以是巢狀結構。 也就是說,主版頁面也可以使用主版頁面。 Blazor 中的配置元件也可以是巢狀結構。 您可以將配置元件套用至配置元件。 內部配置的內容將在外部配置內進行轉譯。

ChildLayout.razor

@layout MainLayout
<h2>Child layout</h2>
<div>
    @Body
</div>

Index.razor

@page "/"
@layout ChildLayout
<p>I'm in a nested layout!</p>

接著,頁面的轉譯輸出會是:

<h1>Main layout</h1>
<div>
    <h2>Child layout</h2>
    <div>
        <p>I'm in a nested layout!</p>
    </div>
</div>

Blazor 中的配置通常不會定義頁面的根 HTML 元素 (<html><body><head> 等等)。 根 HTML 元素會改為定義於 Blazor 應用程式的主機頁面中,其可用來轉譯應用程式的初始 HTML 內容 (請參閱啟動 Blazor)。 主機頁面可以為具有周圍標記的應用程式轉譯多個根元件。

Blazor 中的元件 (包括頁面) 無法轉譯 <script> 標記。 此轉譯限制存在的原因,是因為 <script> 標記只能載入一次,接著便無法變更。 如果您嘗試使用 Razor 語法動態轉譯標記,可能就會發生非預期的行為。 相反地,所有 <script> 標記都應該新增至應用程式的主機頁面。