Layouts Blazor do ASP.NET Core

Observação

Esta não é a versão mais recente deste artigo. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Importante

Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.

Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Este artigo explica como criar componentes de layout reutilizáveis para aplicativos Blazor.

Utilidade dos layouts Blazor

Alguns elementos do aplicativo, como menus, mensagens de direitos autorais e logotipos da empresa, geralmente fazem parte da apresentação geral do aplicativo. A colocação de uma cópia da marcação desses elementos em todos os componentes de um aplicativo não é eficiente. Sempre que um desses elementos é atualizado, todos os componentes que usam o elemento devem ser atualizados. Essa abordagem pode custar caro para ser mantida e pode gerar um conteúdo inconsistente se uma atualização for perdida. Os layouts resolvem esses problemas.

Um layout de Blazor é um componente de Razor que compartilha a marcação com componentes que fazem referência a ele. Os layouts podem usar associação de dados, injeção de dependência e outros recursos de componentes.

Componentes do layout

Criar um componente de layout

Para criar um componente de layout:

  • Crie um componente Razor definido por um modelo Razor ou código C#. Os componentes de layout baseados em um modelo Razor usam a extensão de arquivo .razor, assim como os componentes Razor comuns. Como os componentes de layout são compartilhados entre os componentes de um aplicativo, eles geralmente são colocados na pasta Shared ou Layout do aplicativo. No entanto, os layouts podem ser colocados em qualquer local acessível aos componentes que o usam. Por exemplo, um layout pode ser colocado na mesma pasta que os componentes que o usam.
  • Herda o componente de LayoutComponentBase. O LayoutComponentBase define uma propriedade Body (tipo RenderFragment) para o conteúdo renderizado dentro do layout.
  • Use a sintaxe Razor@Body para especificar o local na marcação de layout em que o conteúdo é renderizado.

Observação

Para obter mais informações sobre RenderFragment, confira Componentes Razordo ASP.NET Core.

O componente DoctorWhoLayout a seguir mostra o modelo Razor de um componente de layout. O layout herda LayoutComponentBase e define o @Body entre a barra de navegação (<nav>...</nav>) e o rodapé (<footer>...</footer>).

DoctorWhoLayout.razor:

@inherits LayoutComponentBase

<PageTitle>Doctor Who® Database</PageTitle>

<header>
    <h1>Doctor Who® Database</h1>
</header>

<nav>
    <a href="main-list">Main Episode List</a>
    <a href="search">Search</a>
    <a href="new">Add Episode</a>
</nav>

@Body

<footer>
    @TrademarkMessage
</footer>

@code {
    public string TrademarkMessage { get; set; } =
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/ https://www.bbc.com";
}
@inherits LayoutComponentBase

<header>
    <h1>Doctor Who™ Episode Database</h1>
</header>

<nav>
    <a href="main-list">Main Episode List</a>
    <a href="search">Search</a>
    <a href="new">Add Episode</a>
</nav>

@Body

<footer>
    @TrademarkMessage
</footer>

@code {
    public string TrademarkMessage { get; set; } = 
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase

<header>
    <h1>Doctor Who™ Episode Database</h1>
</header>

<nav>
    <a href="main-list">Main Episode List</a>
    <a href="search">Search</a>
    <a href="new">Add Episode</a>
</nav>

@Body

<footer>
    @TrademarkMessage
</footer>

@code {
    public string TrademarkMessage { get; set; } = 
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase

<header>
    <h1>Doctor Who™ Episode Database</h1>
</header>

<nav>
    <a href="main-list">Main Episode List</a>
    <a href="search">Search</a>
    <a href="new">Add Episode</a>
</nav>

@Body

<footer>
    @TrademarkMessage
</footer>

@code {
    public string TrademarkMessage { get; set; } = 
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase

<header>
    <h1>Doctor Who™ Episode Database</h1>
</header>

<nav>
    <a href="main-list">Main Episode List</a>
    <a href="search">Search</a>
    <a href="new">Add Episode</a>
</nav>

@Body

<footer>
    @TrademarkMessage
</footer>

@code {
    public string TrademarkMessage { get; set; } = 
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/";
}

componente MainLayout

Em um aplicativo criado com base em um modelo de projeto Blazor, o componente MainLayout é o layout padrão do aplicativo. O layout do Blazor adota a Flexbox layout model (MDN documentation) (especificação W3C).

O recurso de isolamento CSS do Blazor aplica estilos CSS isolados ao componente MainLayout. Por convenção, os estilos são fornecidos pela folha de estilos que acompanha o mesmo nome, MainLayout.razor.css. A implementação da estrutura ASP.NET Core da folha de estilos está disponível para inspeção na fonte de referência do ASP.NET Core (repositório GitHub dotnet/aspnetcore):

Observação

Os links de documentação para a fonte de referência do .NET geralmente carregam o branch padrão do repositório, que representa o desenvolvimento atual da próxima versão do .NET. Para selecionar uma marca para uma versão específica, use a lista suspensa para Alternar branches ou marcas. Para saber mais, confira Como selecionar uma marca de versão do código-fonte do ASP.NET Core (dotnet/AspNetCore.Docs #26205).

O recurso de isolamento CSS do Blazor aplica estilos CSS isolados ao componente MainLayout. Por convenção, os estilos são fornecidos pela folha de estilos que acompanha o mesmo nome, MainLayout.razor.css. A implementação da estrutura ASP.NET Core da folha de estilos está disponível para inspeção na fonte de referência do ASP.NET Core (repositório GitHub dotnet/aspnetcore):

Observação

Os links de documentação para a fonte de referência do .NET geralmente carregam o branch padrão do repositório, que representa o desenvolvimento atual da próxima versão do .NET. Para selecionar uma marca para uma versão específica, use a lista suspensa para Alternar branches ou marcas. Para saber mais, confira Como selecionar uma marca de versão do código-fonte do ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Aplicar um layout

Disponibilizar o namespace de layout

Locais de arquivo de layout e namespaces alterados ao longo do tempo para a estrutura Blazor. Dependendo da versão de Blazor e do tipo do aplicativo Blazor que você está criando, talvez seja necessário indicar o namespace do layout ao usá-lo. Ao referenciar uma implementação de layout e o layout não for encontrado sem indicar o namespace do layout, siga qualquer uma das seguintes abordagens:

  • Adicione uma diretiva @using ao arquivo _Imports.razor para o local dos layouts. No exemplo a seguir, uma pasta de layouts com o nome Layout está dentro de uma pasta Components e o namespace do aplicativo é BlazorSample:

    @using BlazorSample.Components.Layout
    
  • Adicione uma diretiva @using na parte superior da definição do componente em que o layout é usado:

    @using BlazorSample.Components.Layout
    @layout DoctorWhoLayout
    
  • Qualifique totalmente o namespace do layout em que ele é usado:

    @layout BlazorSample.Components.Layout.DoctorWhoLayout
    

Aplicar um layout a um componente

Use a diretiva @layoutRazor para aplicar um layout a um componente Razor roteável que tenha uma diretiva @page. O compilador converte @layout em um LayoutAttribute e aplica o atributo à classe de componente.

O conteúdo do componente Episodes a seguir é inserido no DoctorWhoLayout na posição de @Body.

Episodes.razor:

@page "/episodes"
@layout DoctorWhoLayout

<h2>Doctor Who® Episodes</h2>

<ul>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfknq">
            <em>The Ribos Operation</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfdsb">
            <em>The Sunmakers</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vhc26">
            <em>Nightmare of Eden</em>
        </a>
    </li>
</ul>
@page "/episodes"
@layout DoctorWhoLayout

<h2>Episodes</h2>

<ul>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfknq">
            <em>The Ribos Operation</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfdsb">
            <em>The Sun Makers</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vhc26">
            <em>Nightmare of Eden</em>
        </a>
    </li>
</ul>
@page "/episodes"
@layout DoctorWhoLayout

<h2>Episodes</h2>

<ul>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfknq">
            <em>The Ribos Operation</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfdsb">
            <em>The Sun Makers</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vhc26">
            <em>Nightmare of Eden</em>
        </a>
    </li>
</ul>
@page "/episodes"
@layout DoctorWhoLayout

<h2>Episodes</h2>

<ul>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfknq">
            <em>The Ribos Operation</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfdsb">
            <em>The Sun Makers</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vhc26">
            <em>Nightmare of Eden</em>
        </a>
    </li>
</ul>

A marcação HTML renderizada a seguir é produzida pelo componente anterior DoctorWhoLayout e Episodes. A marcação desnecessária não aparece para se concentrar no conteúdo fornecido pelos dois componentes envolvidos:

  • O título H1 do "banco de dados" (<h1>...</h1>) no cabeçalho (<header>...</header>), a barra de navegação (<nav>...</nav>) e as informações de marca registrada no rodapé (<footer>...</footer>) são provenientes do componente DoctorWhoLayout.
  • O título H2 "episódios" (<h2>...</h2>) e a lista de episódios (<ul>...</ul>) vêm do componente Episodes.
<header>
    <h1 ...>...</h1>
</header>

<nav>
    ...
</nav>

<h2>...</h2>

<ul>
    <li>...</li>
    <li>...</li>
    <li>...</li>
</ul>

<footer>
    ...
</footer>

A especificação do layout diretamente em um componente substitui um layout padrão:

Aplicar um layout a uma pasta de componentes

Cada pasta de um aplicativo pode, opcionalmente, conter um arquivo de modelo nomeado _Imports.razor. O compilador inclui as diretivas especificadas no arquivo de importações em todos os modelos Razor na mesma pasta e recursivamente em todas as suas subpastas. Portanto, um arquivo _Imports.razor que contém @layout DoctorWhoLayout garante que todos os componentes em uma pasta usem o componente DoctorWhoLayout. Não é necessário adicionar @layout DoctorWhoLayout repetidamente a todos os componentes Razor (.razor) dentro da pasta e das subpastas.

_Imports.razor:

@layout DoctorWhoLayout
...

O arquivo _Imports.razor é semelhante ao arquivo _ViewImports.cshtml para exibições Razor e páginas, mas aplicado especificamente aos arquivos de componente Razor.

A especificação de um layout em _Imports.razor substitui um layout especificado como layout de aplicativo padrão do roteador, que é descrito na seção a seguir.

Aviso

Não adicione uma diretiva Razor@layout ao arquivo _Imports.razor raiz, o que resulta em um loop infinito de layouts. Para controlar o layout do aplicativo padrão, especifique o layout no componente Router. Para obter mais informações, consulte a seção Aplicar um layout padrão a um aplicativo a seguir.

Observação

A diretiva @layoutRazor aplica apenas um layout a componentes roteáveis Razor com uma diretiva @page.

Aplicar um layout padrão a um aplicativo

Especifique o layout do aplicativo padrão no componente RouteView do componente Router. Use o parâmetro DefaultLayout para definir o tipo de layout:

<RouteView RouteData="routeData" DefaultLayout="typeof({LAYOUT})" />

No exemplo anterior, o espaço reservado {LAYOUT} é o layout (por exemplo, DoctorWhoLayout se o nome do arquivo de layout for DoctorWhoLayout.razor). Talvez seja necessário identificar o namespace do layout, dependendo da versão do .NET e do tipo do aplicativo Blazor. Para obter mais informações, consulte a seção Disponibilizar o namespace de layout.

A especificação do layout como um layout padrão no Router do RouteView do componente é uma prática útil porque você pode substituir o layout por componente ou por pasta, conforme descrito nas seções anteriores deste artigo. É recomendável usar o componente Router para definir o layout padrão do aplicativo, pois ele é a abordagem mais geral e flexível para usar layouts.

Aplicar um layout ao conteúdo arbitrário (componente LayoutView)

Para definir um layout para conteúdo de modelo arbitrário Razor, especifique o layout com um componente LayoutView. Você pode usar um LayoutView em qualquer componente Razor. O exemplo a seguir define um componente de layout nomeado ErrorLayout para o modelo NotFound do componente MainLayout (<NotFound>...</NotFound>).

<Router ...>
    <Found ...>
        ...
    </Found>
    <NotFound>
        <LayoutView Layout="typeof(ErrorLayout)">
            <h1>Page not found</h1>
            <p>Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

Talvez seja necessário identificar o namespace do layout, dependendo da versão do .NET e do tipo do aplicativo Blazor. Para obter mais informações, consulte a seção Disponibilizar o namespace de layout.

Importante

Blazor Os Aplicativos Web não usam o parâmetro NotFound (marcação <NotFound>...</NotFound>), mas o parâmetro tem suporte para compatibilidade com versões anteriores, a fim de evitar uma alteração interruptiva na estrutura. O pipeline de middleware ASP.NET Core do lado do servidor processa solicitações no servidor. Use as técnicas do servidor para tratar as solicitações incorretas. Para obter mais informações, consulte ASP.NET Core Blazor modos de renderização.

Observação

Com a versão do ASP.NET Core 5.0.1 e para qualquer lançamento adicional do 5.x, o componente Router inclui o parâmetro PreferExactMatches definido como @true. Para obter mais informações, consulte Migrar do ASP.NET Core 3.1 para o 5.0.

Layouts aninhados

Um componente pode fazer referência a um layout que, por sua vez, faz referência a outro layout. Por exemplo, layouts aninhados são usados para criar estruturas de menu de vários níveis.

O exemplo a seguir mostra como usar os layouts aninhados. O componente Episodes mostrado na seção Aplicar um layout a um componente é o componente a ser exibido. O componente faz referência ao componente DoctorWhoLayout.

O componente DoctorWhoLayout a seguir é uma versão modificada do exemplo mostrado anteriormente neste artigo. Os elementos de cabeçalho e rodapé são removidos e o layout faz referência a outro layout, ProductionsLayout. O componente Episodes é renderizado onde @Body aparece no DoctorWhoLayout.

DoctorWhoLayout.razor:

@inherits LayoutComponentBase
@layout ProductionsLayout

<PageTitle>Doctor Who® Database</PageTitle>

<h1>Doctor Who® Database</h1>

<nav>
    <a href="main-episode-list">Main Episode List</a>
    <a href="episode-search">Search</a>
    <a href="new-episode">Add Episode</a>
</nav>

@Body

<div>
    @TrademarkMessage
</div>

@code {
    public string TrademarkMessage { get; set; } =
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/ https://www.bbc.com";
}
@inherits LayoutComponentBase
@layout ProductionsLayout

<h1>Doctor Who™ Episode Database</h1>

<nav>
    <a href="main-episode-list">Main Episode List</a>
    <a href="episode-search">Search</a>
    <a href="new-episode">Add Episode</a>
</nav>

@Body

<div>
    @TrademarkMessage
</div>

@code {
    public string TrademarkMessage { get; set; } = 
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase
@layout ProductionsLayout

<h1>Doctor Who™ Episode Database</h1>

<nav>
    <a href="main-episode-list">Main Episode List</a>
    <a href="episode-search">Search</a>
    <a href="new-episode">Add Episode</a>
</nav>

@Body

<div>
    @TrademarkMessage
</div>

@code {
    public string TrademarkMessage { get; set; } = 
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase
@layout ProductionsLayout

<h1>Doctor Who™ Episode Database</h1>

<nav>
    <a href="main-episode-list">Main Episode List</a>
    <a href="episode-search">Search</a>
    <a href="new-episode">Add Episode</a>
</nav>

@Body

<div>
    @TrademarkMessage
</div>

@code {
    public string TrademarkMessage { get; set; } = 
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase
@layout ProductionsLayout

<h1>Doctor Who™ Episode Database</h1>

<nav>
    <a href="main-episode-list">Main Episode List</a>
    <a href="episode-search">Search</a>
    <a href="new-episode">Add Episode</a>
</nav>

@Body

<div>
    @TrademarkMessage
</div>

@code {
    public string TrademarkMessage { get; set; } = 
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/";
}

O componente ProductionsLayout contém os elementos de layout de nível superior, em que os elementos de cabeçalho (<header>...</header>) e rodapé (<footer>...</footer>) agora residem. O DoctorWhoLayout com o componente Episodes é renderizado onde @Body aparece.

ProductionsLayout.razor:

@inherits LayoutComponentBase

<header>
    <h1>Productions</h1>
</header>

<nav>
    <a href="main-production-list">Main Production List</a>
    <a href="production-search">Search</a>
    <a href="new-production">Add Production</a>
</nav>

@Body

<footer>
    Footer of Productions Layout
</footer>
@inherits LayoutComponentBase

<header>
    <h1>Productions</h1>
</header>

<nav>
    <a href="main-production-list">Main Production List</a>
    <a href="production-search">Search</a>
    <a href="new-production">Add Production</a>
</nav>

@Body

<footer>
    Footer of Productions Layout
</footer>
@inherits LayoutComponentBase

<header>
    <h1>Productions</h1>
</header>

<nav>
    <a href="main-production-list">Main Production List</a>
    <a href="production-search">Search</a>
    <a href="new-production">Add Production</a>
</nav>

@Body

<footer>
    Footer of Productions Layout
</footer>
@inherits LayoutComponentBase

<header>
    <h1>Productions</h1>
</header>

<nav>
    <a href="main-production-list">Main Production List</a>
    <a href="production-search">Search</a>
    <a href="new-production">Add Production</a>
</nav>

@Body

<footer>
    Footer of Productions Layout
</footer>
@inherits LayoutComponentBase

<header>
    <h1>Productions</h1>
</header>

<nav>
    <a href="main-production-list">Main Production List</a>
    <a href="production-search">Search</a>
    <a href="new-production">Add Production</a>
</nav>

@Body

<footer>
    Footer of Productions Layout
</footer>

A marcação HTML renderizada a seguir é produzida pelo layout aninhado anterior. A marcação desnecessária não aparece para se concentrar no conteúdo aninhado fornecido pelos três componentes envolvidos:

  • Os elementos de cabeçalho (<header>...</header>), barra de navegação de produção (<nav>...</nav>) e rodapé (<footer>...</footer>) e seu conteúdo são derivados do componente ProductionsLayout.
  • O título H1 do "banco de dados" (<h1>...</h1>), a barra de navegação de episódios (<nav>...</nav>) e as informações de marca registrada (<div>...</div>) vêm do componente DoctorWhoLayout.
  • O título H2 "episódios" (<h2>...</h2>) e a lista de episódios (<ul>...</ul>) vêm do componente Episodes.
<header>
    ...
</header>

<nav>
    <a href="main-production-list">Main Production List</a>
    <a href="production-search">Search</a>
    <a href="new-production">Add Production</a>
</nav>

<h1>...</h1>

<nav>
    <a href="main-episode-list">Main Episode List</a>
    <a href="episode-search">Search</a>
    <a href="new-episode">Add Episode</a>
</nav>

<h2>...</h2>

<ul>
    <li>...</li>
    <li>...</li>
    <li>...</li>
</ul>

<div>
    ...
</div>

<footer>
    ...
</footer>

Compartilhar um layout do Razor Pages com componentes integrados

Quando componentes roteáveis são integrados a um aplicativo Razor Pages, o layout compartilhado do aplicativo pode ser usado com os componentes. Para obter mais informações, consulte Integrar componentes Razor do ASP.NET Core em aplicativos do ASP.NET Core.

Quando componentes roteáveis são integrados a um aplicativo Razor Pages, o layout compartilhado do aplicativo pode ser usado com os componentes. Para obter mais informações, confira Renderizar previamente e integrar os componentes Razor do ASP.NET Core.

Seções

Para controlar o conteúdo em um layout a partir de um componente-filho Razor, consulte as seções ASP.NET Core Blazor.

Recursos adicionais