Diseños de ASP.NET Core Blazor

Algunos elementos de la aplicación, como los menús, los mensajes de copyright y los logotipos de la empresa, suelen formar parte del diseño general de la aplicación. Colocar una copia del marcado de estos elementos en todos los componentes de una aplicación no es eficaz. Cada vez que uno de estos elementos se actualice, deberán actualizarse todos los componentes que dicho elemento use. Este método es costoso de mantener y puede dar lugar a contenido incoherente si una actualización no se lleva a cabo. Los diseños resuelven este tipo de problemas.

Un diseño de Blazor es un componente Razor que comparte el marcado con los componentes que hacen referencia a él. Los diseños pueden usar características de los componentes, como el enlace de datos y la inserción de dependencias, entre otras.

Componentes de diseño

Creación de un componente de diseño

Para crear un componente de diseño:

  • Cree un componente Razor definido por una plantilla Razor o código de C#. Los componentes de diseño basados en una plantilla Razor usan la extensión de archivo .razor, igual que cualquier otro componente Razor normal. Dado que los componentes de diseño se comparten entre los componentes de una aplicación, se suelen colocar en la carpeta Shared de la aplicación, pero pueden colocarse en cualquier ubicación a la que tengan acceso los componentes que lo usan. Por ejemplo, un diseño se puede colocar en la misma carpeta que los componentes que lo usan.
  • Herede el componente de LayoutComponentBase. LayoutComponentBase define una propiedad Body (de tipo RenderFragment) para el contenido representado dentro del diseño.
  • Use la sintaxis @Body de Razor para especificar la ubicación en el marcado de diseño donde se representa el contenido.

El siguiente componente DoctorWhoLayout muestra la plantilla Razor de un componente de diseño. El diseño hereda LayoutComponentBase y establece @Body entre la barra de navegación (<nav>...</nav>) y el pie de página (<footer>...</footer>).

Shared/DoctorWhoLayout.razor:

@inherits LayoutComponentBase

<header>
    <h1>Doctor Who&trade; Episode Database</h1>
</header>

<nav>
    <a href="masterlist">Master 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 de MainLayout

En una aplicación creada a partir de una plantilla de proyecto de Blazor, el componente MainLayout es el diseño predeterminado de la aplicación.

Shared/MainLayout.razor:

@inherits LayoutComponentBase

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <div class="main">
        <div class="top-row px-4">
            <a href="http://blazor.net" target="_blank" class="ml-md-auto">About</a>
        </div>

        <div class="content px-4">
            @Body
        </div>
    </div>
</div>

La característica de aislamiento CSS de Blazor aplica estilos CSS aislados al componente MainLayout. Por convención, los estilos los proporciona la hoja de estilos del mismo nombre que los acompaña, Shared/MainLayout.razor.css. La implementación del marco ASP.NET Core de la hoja de estilos está disponible para su inspección en Origen de referencia de ASP.NET Core (repositorio de GitHub dotnet/aspnetcore).

Nota

Los enlaces de la documentación del origen de referencia de ASP.NET Core cargan la rama main del repositorio, que representa el desarrollo actual de la unidad de producto para la próxima versión de ASP.NET Core. Para seleccionar la rama de una versión diferente, use la lista desplegable Switch branches or tags (Cambiar ramas o etiquetas) para seleccionar la rama. Por ejemplo, seleccione la rama release/5.0 para la versión 5.0 de ASP.NET Core.

Aplicación de un diseño

Aplicación de diseño a un componente

Use la directiva @layout de Razor para aplicar un diseño a un componente de Razor enrutable que tenga una directiva @page. El compilador convierte @layout en LayoutAttribute y aplica el atributo a la clase de componente.

El contenido del siguiente componente Episodes se inserta en DoctorWhoLayout en la posición @Body.

Pages/Episodes.razor:

@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>

El siguiente marcado HTML representado lo genera el componente DoctorWhoLayout anterior y el componente Episodes. El marcado extraño no se muestra para centrarnos en el contenido proporcionado por los dos componentes implicados:

  • El título Doctor Who™ Episode Database (<h1>...</h1>) del encabezado (<header>...</header>), la barra de navegación (<nav>...</nav>) y el elemento informativo de marca comercial (<div>...</div>) del pie de página (<footer>...</footer>) proceden del componente DoctorWhoLayout.
  • El título Episodes (<h2>...</h2>) y la lista de episodios (<ul>...</ul>) proceden del componente Episodes.
<body>
    <div id="app">
        <header>
            <h1>Doctor Who&trade; 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>

        <h2>Episodes</h2>

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

        <footer>
            Doctor Who is a registered trademark of the BBC. 
            https://www.doctorwho.tv/
        </footer>
    </div>
</body>

Al especificar el diseño directamente en un componente, se reemplaza un diseño predeterminado que:

Aplicación de un diseño a una carpeta de componentes

Cada una de las carpetas de una aplicación puede contener opcionalmente un archivo de plantilla denominado _Imports.razor. El compilador incluye las directivas especificadas en el archivo de importaciones de todas las plantillas de Razor de la misma carpeta y, de forma recurrente, de todas sus subcarpetas. Por lo tanto, un archivo _Imports.razor que contiene @layout DoctorWhoLayout garantiza que todos los componentes de una carpeta usen el componente DoctorWhoLayout. No es necesario agregar continuamente @layout DoctorWhoLayout a todos los componentes Razor (.razor) dentro de la carpeta y las subcarpetas.

_Imports.razor:

@layout DoctorWhoLayout
...

El archivo _Imports.razor es similar al archivo _ViewImports.cshtml de las vistas y las páginas de Razor, aunque se aplica específicamente a los archivos de componentes de Razor.

Cuando se especifica un diseño en _Imports.razor, este reemplaza el diseño especificado como diseño de la aplicación predeterminado del enrutador. Esto se describe en la siguiente sección.

Advertencia

No agregue una directiva @layout de Razor al archivo raíz _Imports.razor, que da como resultado un bucle infinito de diseños. Para controlar el diseño predeterminado de la aplicación, especifique el diseño en el componente Router. Para obtener más información, vea la sección Aplicación de un diseño predeterminado a una aplicación.

Nota

La directiva @layout de Razor únicamente aplica un diseño a los componentes Razor enrutables con una directiva @page.

Aplicación de un diseño predeterminado a una aplicación

Especifique el diseño predeterminado de la aplicación en el componente Router del componente App. En el siguiente ejemplo de una aplicación basada en una plantilla de proyecto de Blazor, el diseño predeterminado se establece en el componente MainLayout.

App.razor:

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

Para obtener más información sobre el componente Router, consulte el artículo Enrutamiento de Blazor de ASP.NET Core.

Especificar el diseño como un diseño predeterminado en el componente Router es útil en el sentido de que permite reemplazar el diseño según el componente o la carpeta, como se describe en las secciones anteriores de este artículo. Se recomienda usar el componente Router para establecer el diseño predeterminado de la aplicación, ya que es el método más general y flexible de uso de diseños.

Aplicación de un diseño a contenido arbitrario (componente LayoutView)

Para establecer el diseño del contenido arbitrario de una plantilla Razor, especifique el diseño con un componente LayoutView. LayoutView se puede usar en cualquier componente Razor. En el siguiente ejemplo se establece un componente de diseño denominado ErrorLayout para la plantilla NotFound del componente MainLayout (<NotFound>...</NotFound>).

App.razor:

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

Diseños anidados

Un componente puede hacer referencia a un diseño que, a su vez, hace referencia a otro diseño. Por ejemplo, los diseños anidados se usan para crear una estructura de menú de varios niveles.

En el ejemplo siguiente se muestra cómo usar los diseños anidados. El componente Episodes de la sección Aplicación de un diseño a un componente es el componente que se va a mostrar. El componente hace referencia al componente DoctorWhoLayout.

El siguiente componente DoctorWhoLayout es una versión modificada del ejemplo que vimos antes en este artículo. Se le han quitado los elementos de encabezado y pie de página, y el diseño hace referencia a otro diseño, ProductionsLayout. El componente Episodes se representa cuando @Body aparece en DoctorWhoLayout.

Shared/DoctorWhoLayout.razor:

@inherits LayoutComponentBase
@layout ProductionsLayout

<h1>Doctor Who&trade; Episode Database</h1>

<nav>
    <a href="episode-masterlist">Master 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/";
}

El componente ProductionsLayout contiene los elementos de diseño de nivel superior, donde ahora están los elementos de encabezado (<header>...</header>) y pie de página (<footer>...</footer>). El componente DoctorWhoLayout con el componente Episodes se representa donde aparezca @Body.

Shared/ProductionsLayout.razor:

@inherits LayoutComponentBase

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

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

@Body

<footer>
    Footer of Productions Layout
</footer>

El siguiente marcado HTML representado lo genera el diseño anidado anterior. El marcado extraño no se muestra para centrarnos en el contenido anidado proporcionado por los tres componentes implicados:

  • Los elementos de encabezado (<header>...</header>), barra de navegación de producción (<nav>...</nav>) y pie de página (<footer>...</footer>), y su contenido proceden del componente ProductionsLayout.
  • El título Doctor Who™ Episode Database (<h1>...</h1>), la barra de navegación de episodios (<nav>...</nav>) y el elemento informativo de marca comercial (<div>...</div>) proceden del componente DoctorWhoLayout.
  • El título Episodes (<h2>...</h2>) y la lista de episodios (<ul>...</ul>) proceden del componente Episodes.
<body>
    <div id="app">
        <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>

        <h1>Doctor Who&trade; Episode Database</h1>

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

        <h2>Episodes</h2>

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

        <div>
            Doctor Who is a registered trademark of the BBC. 
            https://www.doctorwho.tv/
        </div>

        <footer>
            Footer of Productions Layout
        </footer>
    </div>
</body>

Uso compartido de un diseño de Razor Pages con componentes integrados

Si los componentes enrutables se integran en una aplicación de Razor Pages, el diseño compartido de la aplicación se puede usar con los componentes. Para obtener más información, vea Integración y representación previa de componentes Razor de ASP.NET Core.

Recursos adicionales

Algunos elementos de la aplicación, como los menús, los mensajes de copyright y los logotipos de la empresa, suelen formar parte del diseño general de la aplicación. Colocar una copia del marcado de estos elementos en todos los componentes de una aplicación no es eficaz. Cada vez que uno de estos elementos se actualice, deberán actualizarse todos los componentes que dicho elemento use. Este método es costoso de mantener y puede dar lugar a contenido incoherente si una actualización no se lleva a cabo. Los diseños resuelven este tipo de problemas.

Un diseño de Blazor es un componente Razor que comparte el marcado con los componentes que hacen referencia a él. Los diseños pueden usar características de los componentes, como el enlace de datos y la inserción de dependencias, entre otras.

Componentes de diseño

Creación de un componente de diseño

Para crear un componente de diseño:

  • Cree un componente Razor definido por una plantilla Razor o código de C#. Los componentes de diseño basados en una plantilla Razor usan la extensión de archivo .razor, igual que cualquier otro componente Razor normal. Dado que los componentes de diseño se comparten entre los componentes de una aplicación, se suelen colocar en la carpeta Shared de la aplicación, pero pueden colocarse en cualquier ubicación a la que tengan acceso los componentes que lo usan. Por ejemplo, un diseño se puede colocar en la misma carpeta que los componentes que lo usan.
  • Herede el componente de LayoutComponentBase. LayoutComponentBase define una propiedad Body (de tipo RenderFragment) para el contenido representado dentro del diseño.
  • Use la sintaxis @Body de Razor para especificar la ubicación en el marcado de diseño donde se representa el contenido.

El siguiente componente DoctorWhoLayout muestra la plantilla Razor de un componente de diseño. El diseño hereda LayoutComponentBase y establece @Body entre la barra de navegación (<nav>...</nav>) y el pie de página (<footer>...</footer>).

Shared/DoctorWhoLayout.razor:

@inherits LayoutComponentBase

<header>
    <h1>Doctor Who&trade; Episode Database</h1>
</header>

<nav>
    <a href="masterlist">Master 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 de MainLayout

En una aplicación creada a partir de una plantilla de proyecto de Blazor, el componente MainLayout es el diseño predeterminado de la aplicación.

Shared/MainLayout.razor:

@inherits LayoutComponentBase

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <div class="main">
        <div class="top-row px-4">
            <a href="http://blazor.net" target="_blank" class="ml-md-auto">About</a>
        </div>

        <div class="content px-4">
            @Body
        </div>
    </div>
</div>

La característica de aislamiento CSS de Blazor aplica estilos CSS aislados al componente MainLayout. Por convención, los estilos los proporciona la hoja de estilos del mismo nombre que los acompaña, Shared/MainLayout.razor.css. La implementación del marco ASP.NET Core de la hoja de estilos está disponible para su inspección en Origen de referencia de ASP.NET Core (repositorio de GitHub dotnet/aspnetcore).

Nota

Los enlaces de la documentación del origen de referencia de ASP.NET Core cargan la rama main del repositorio, que representa el desarrollo actual de la unidad de producto para la próxima versión de ASP.NET Core. Para seleccionar la rama de una versión diferente, use la lista desplegable Switch branches or tags (Cambiar ramas o etiquetas) para seleccionar la rama. Por ejemplo, seleccione la rama release/5.0 para la versión 5.0 de ASP.NET Core.

Aplicación de un diseño

Aplicación de diseño a un componente

Use la directiva @layout de Razor para aplicar un diseño a un componente de Razor enrutable que tenga una directiva @page. El compilador convierte @layout en LayoutAttribute y aplica el atributo a la clase de componente.

El contenido del siguiente componente Episodes se inserta en DoctorWhoLayout en la posición @Body.

Pages/Episodes.razor:

@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>

El siguiente marcado HTML representado lo genera el componente DoctorWhoLayout anterior y el componente Episodes. El marcado extraño no se muestra para centrarnos en el contenido proporcionado por los dos componentes implicados:

  • El título Doctor Who™ Episode Database (<h1>...</h1>) del encabezado (<header>...</header>), la barra de navegación (<nav>...</nav>) y el elemento informativo de marca comercial (<div>...</div>) del pie de página (<footer>...</footer>) proceden del componente DoctorWhoLayout.
  • El título Episodes (<h2>...</h2>) y la lista de episodios (<ul>...</ul>) proceden del componente Episodes.
<body>
    <div id="app">
        <header>
            <h1>Doctor Who&trade; 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>

        <h2>Episodes</h2>

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

        <footer>
            Doctor Who is a registered trademark of the BBC. 
            https://www.doctorwho.tv/
        </footer>
    </div>
</body>

Al especificar el diseño directamente en un componente, se reemplaza un diseño predeterminado que:

Aplicación de un diseño a una carpeta de componentes

Cada una de las carpetas de una aplicación puede contener opcionalmente un archivo de plantilla denominado _Imports.razor. El compilador incluye las directivas especificadas en el archivo de importaciones de todas las plantillas de Razor de la misma carpeta y, de forma recurrente, de todas sus subcarpetas. Por lo tanto, un archivo _Imports.razor que contiene @layout DoctorWhoLayout garantiza que todos los componentes de una carpeta usen el componente DoctorWhoLayout. No es necesario agregar continuamente @layout DoctorWhoLayout a todos los componentes Razor (.razor) dentro de la carpeta y las subcarpetas.

_Imports.razor:

@layout DoctorWhoLayout
...

El archivo _Imports.razor es similar al archivo _ViewImports.cshtml de las vistas y las páginas de Razor, aunque se aplica específicamente a los archivos de componentes de Razor.

Cuando se especifica un diseño en _Imports.razor, este reemplaza el diseño especificado como diseño de la aplicación predeterminado del enrutador. Esto se describe en la siguiente sección.

Advertencia

No agregue una directiva @layout de Razor al archivo raíz _Imports.razor, que da como resultado un bucle infinito de diseños. Para controlar el diseño predeterminado de la aplicación, especifique el diseño en el componente Router. Para obtener más información, vea la sección Aplicación de un diseño predeterminado a una aplicación.

Nota

La directiva @layout de Razor únicamente aplica un diseño a los componentes Razor enrutables con una directiva @page.

Aplicación de un diseño predeterminado a una aplicación

Especifique el diseño predeterminado de la aplicación en el componente Router del componente App. En el siguiente ejemplo de una aplicación basada en una plantilla de proyecto de Blazor, el diseño predeterminado se establece en el componente MainLayout.

App.razor:

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

Nota

Con la publicación de ASP.NET Core 5.0.1 y para las versiones 5.x adicionales, el componente Router incluye el parámetro PreferExactMatches establecido en @true. Para más información, consulte Migración de ASP.NET Core 3.1 a 5.0.

Para obtener más información sobre el componente Router, consulte el artículo Enrutamiento de Blazor de ASP.NET Core.

Especificar el diseño como un diseño predeterminado en el componente Router es útil en el sentido de que permite reemplazar el diseño según el componente o la carpeta, como se describe en las secciones anteriores de este artículo. Se recomienda usar el componente Router para establecer el diseño predeterminado de la aplicación, ya que es el método más general y flexible de uso de diseños.

Aplicación de un diseño a contenido arbitrario (componente LayoutView)

Para establecer el diseño del contenido arbitrario de una plantilla Razor, especifique el diseño con un componente LayoutView. LayoutView se puede usar en cualquier componente Razor. En el siguiente ejemplo se establece un componente de diseño denominado ErrorLayout para la plantilla NotFound del componente MainLayout (<NotFound>...</NotFound>).

App.razor:

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

Nota

Con la publicación de ASP.NET Core 5.0.1 y para las versiones 5.x adicionales, el componente Router incluye el parámetro PreferExactMatches establecido en @true. Para más información, consulte Migración de ASP.NET Core 3.1 a 5.0.

Diseños anidados

Un componente puede hacer referencia a un diseño que, a su vez, hace referencia a otro diseño. Por ejemplo, los diseños anidados se usan para crear una estructura de menú de varios niveles.

En el ejemplo siguiente se muestra cómo usar los diseños anidados. El componente Episodes de la sección Aplicación de un diseño a un componente es el componente que se va a mostrar. El componente hace referencia al componente DoctorWhoLayout.

El siguiente componente DoctorWhoLayout es una versión modificada del ejemplo que vimos antes en este artículo. Se le han quitado los elementos de encabezado y pie de página, y el diseño hace referencia a otro diseño, ProductionsLayout. El componente Episodes se representa cuando @Body aparece en DoctorWhoLayout.

Shared/DoctorWhoLayout.razor:

@inherits LayoutComponentBase
@layout ProductionsLayout

<h1>Doctor Who&trade; Episode Database</h1>

<nav>
    <a href="episode-masterlist">Master 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/";
}

El componente ProductionsLayout contiene los elementos de diseño de nivel superior, donde ahora están los elementos de encabezado (<header>...</header>) y pie de página (<footer>...</footer>). El componente DoctorWhoLayout con el componente Episodes se representa donde aparezca @Body.

Shared/ProductionsLayout.razor:

@inherits LayoutComponentBase

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

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

@Body

<footer>
    Footer of Productions Layout
</footer>

El siguiente marcado HTML representado lo genera el diseño anidado anterior. El marcado extraño no se muestra para centrarnos en el contenido anidado proporcionado por los tres componentes implicados:

  • Los elementos de encabezado (<header>...</header>), barra de navegación de producción (<nav>...</nav>) y pie de página (<footer>...</footer>), y su contenido proceden del componente ProductionsLayout.
  • El título Doctor Who™ Episode Database (<h1>...</h1>), la barra de navegación de episodios (<nav>...</nav>) y el elemento informativo de marca comercial (<div>...</div>) proceden del componente DoctorWhoLayout.
  • El título Episodes (<h2>...</h2>) y la lista de episodios (<ul>...</ul>) proceden del componente Episodes.
<body>
    <div id="app">
        <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>

        <h1>Doctor Who&trade; Episode Database</h1>

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

        <h2>Episodes</h2>

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

        <div>
            Doctor Who is a registered trademark of the BBC. 
            https://www.doctorwho.tv/
        </div>

        <footer>
            Footer of Productions Layout
        </footer>
    </div>
</body>

Uso compartido de un diseño de Razor Pages con componentes integrados

Si los componentes enrutables se integran en una aplicación de Razor Pages, el diseño compartido de la aplicación se puede usar con los componentes. Para obtener más información, vea Integración y representación previa de componentes Razor de ASP.NET Core.

Recursos adicionales

Algunos elementos de la aplicación, como los menús, los mensajes de copyright y los logotipos de la empresa, suelen formar parte del diseño general de la aplicación. Colocar una copia del marcado de estos elementos en todos los componentes de una aplicación no es eficaz. Cada vez que uno de estos elementos se actualice, deberán actualizarse todos los componentes que dicho elemento use. Este método es costoso de mantener y puede dar lugar a contenido incoherente si una actualización no se lleva a cabo. Los diseños resuelven este tipo de problemas.

Un diseño de Blazor es un componente Razor que comparte el marcado con los componentes que hacen referencia a él. Los diseños pueden usar características de los componentes, como el enlace de datos y la inserción de dependencias, entre otras.

Componentes de diseño

Creación de un componente de diseño

Para crear un componente de diseño:

  • Cree un componente Razor definido por una plantilla Razor o código de C#. Los componentes de diseño basados en una plantilla Razor usan la extensión de archivo .razor, igual que cualquier otro componente Razor normal. Dado que los componentes de diseño se comparten entre los componentes de una aplicación, se suelen colocar en la carpeta Shared de la aplicación, pero pueden colocarse en cualquier ubicación a la que tengan acceso los componentes que lo usan. Por ejemplo, un diseño se puede colocar en la misma carpeta que los componentes que lo usan.
  • Herede el componente de LayoutComponentBase. LayoutComponentBase define una propiedad Body (de tipo RenderFragment) para el contenido representado dentro del diseño.
  • Use la sintaxis @Body de Razor para especificar la ubicación en el marcado de diseño donde se representa el contenido.

El siguiente componente DoctorWhoLayout muestra la plantilla Razor de un componente de diseño. El diseño hereda LayoutComponentBase y establece @Body entre la barra de navegación (<nav>...</nav>) y el pie de página (<footer>...</footer>).

Shared/DoctorWhoLayout.razor:

@inherits LayoutComponentBase

<header>
    <h1>Doctor Who&trade; Episode Database</h1>
</header>

<nav>
    <a href="masterlist">Master 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 de MainLayout

En una aplicación creada a partir de una plantilla de proyecto de Blazor, el componente MainLayout es el diseño predeterminado de la aplicación.

Shared/MainLayout.razor:

@inherits LayoutComponentBase

<div class="sidebar">
    <NavMenu />
</div>

<div class="main">
    <div class="top-row px-4">
        <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
    </div>

    <div class="content px-4">
        @Body
    </div>
</div>

Aplicación de un diseño

Aplicación de diseño a un componente

Use la directiva @layout de Razor para aplicar un diseño a un componente de Razor enrutable que tenga una directiva @page. El compilador convierte @layout en LayoutAttribute y aplica el atributo a la clase de componente.

El contenido del siguiente componente Episodes se inserta en DoctorWhoLayout en la posición @Body.

Pages/Episodes.razor:

@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>

El siguiente marcado HTML representado lo genera el componente DoctorWhoLayout anterior y el componente Episodes. El marcado extraño no se muestra para centrarnos en el contenido proporcionado por los dos componentes implicados:

  • El título Doctor Who™ Episode Database (<h1>...</h1>) del encabezado (<header>...</header>), la barra de navegación (<nav>...</nav>) y el elemento informativo de marca comercial (<div>...</div>) del pie de página (<footer>...</footer>) proceden del componente DoctorWhoLayout.
  • El título Episodes (<h2>...</h2>) y la lista de episodios (<ul>...</ul>) proceden del componente Episodes.
<body>
    <div id="app">
        <header>
            <h1>Doctor Who&trade; 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>

        <h2>Episodes</h2>

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

        <footer>
            Doctor Who is a registered trademark of the BBC. 
            https://www.doctorwho.tv/
        </footer>
    </div>
</body>

Al especificar el diseño directamente en un componente, se reemplaza un diseño predeterminado que:

Aplicación de un diseño a una carpeta de componentes

Cada una de las carpetas de una aplicación puede contener opcionalmente un archivo de plantilla denominado _Imports.razor. El compilador incluye las directivas especificadas en el archivo de importaciones de todas las plantillas de Razor de la misma carpeta y, de forma recurrente, de todas sus subcarpetas. Por lo tanto, un archivo _Imports.razor que contiene @layout DoctorWhoLayout garantiza que todos los componentes de una carpeta usen el componente DoctorWhoLayout. No es necesario agregar continuamente @layout DoctorWhoLayout a todos los componentes Razor (.razor) dentro de la carpeta y las subcarpetas.

_Imports.razor:

@layout DoctorWhoLayout
...

El archivo _Imports.razor es similar al archivo _ViewImports.cshtml de las vistas y las páginas de Razor, aunque se aplica específicamente a los archivos de componentes de Razor.

Cuando se especifica un diseño en _Imports.razor, este reemplaza el diseño especificado como diseño de la aplicación predeterminado del enrutador. Esto se describe en la siguiente sección.

Advertencia

No agregue una directiva @layout de Razor al archivo raíz _Imports.razor, que da como resultado un bucle infinito de diseños. Para controlar el diseño predeterminado de la aplicación, especifique el diseño en el componente Router. Para obtener más información, vea la sección Aplicación de un diseño predeterminado a una aplicación.

La directiva @layout de Razor únicamente aplica un diseño a los componentes Razor enrutables con una directiva @page.

Aplicación de un diseño predeterminado a una aplicación

Especifique el diseño predeterminado de la aplicación en el componente Router del componente App. En el siguiente ejemplo de una aplicación basada en una plantilla de proyecto de Blazor, el diseño predeterminado se establece en el componente MainLayout.

App.razor:

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

Para obtener más información sobre el componente Router, consulte el artículo Enrutamiento de Blazor de ASP.NET Core.

Especificar el diseño como un diseño predeterminado en el componente Router es útil en el sentido de que permite reemplazar el diseño según el componente o la carpeta, como se describe en las secciones anteriores de este artículo. Se recomienda usar el componente Router para establecer el diseño predeterminado de la aplicación, ya que es el método más general y flexible de uso de diseños.

Aplicación de un diseño a contenido arbitrario (componente LayoutView)

Para establecer el diseño del contenido arbitrario de una plantilla Razor, especifique el diseño con un componente LayoutView. LayoutView se puede usar en cualquier componente Razor. En el siguiente ejemplo se establece un componente de diseño denominado ErrorLayout para la plantilla NotFound del componente MainLayout (<NotFound>...</NotFound>).

App.razor:

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

Diseños anidados

Un componente puede hacer referencia a un diseño que, a su vez, hace referencia a otro diseño. Por ejemplo, los diseños anidados se usan para crear una estructura de menú de varios niveles.

En el ejemplo siguiente se muestra cómo usar los diseños anidados. El componente Episodes de la sección Aplicación de un diseño a un componente es el componente que se va a mostrar. El componente hace referencia al componente DoctorWhoLayout.

El siguiente componente DoctorWhoLayout es una versión modificada del ejemplo que vimos antes en este artículo. Se le han quitado los elementos de encabezado y pie de página, y el diseño hace referencia a otro diseño, ProductionsLayout. El componente Episodes se representa cuando @Body aparece en DoctorWhoLayout.

Shared/DoctorWhoLayout.razor:

@inherits LayoutComponentBase
@layout ProductionsLayout

<h1>Doctor Who&trade; Episode Database</h1>

<nav>
    <a href="episode-masterlist">Master 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/";
}

El componente ProductionsLayout contiene los elementos de diseño de nivel superior, donde ahora están los elementos de encabezado (<header>...</header>) y pie de página (<footer>...</footer>). El componente DoctorWhoLayout con el componente Episodes se representa donde aparezca @Body.

Shared/ProductionsLayout.razor:

@inherits LayoutComponentBase

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

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

@Body

<footer>
    Footer of Productions Layout
</footer>

El siguiente marcado HTML representado lo genera el diseño anidado anterior. El marcado extraño no se muestra para centrarnos en el contenido anidado proporcionado por los tres componentes implicados:

  • Los elementos de encabezado (<header>...</header>), barra de navegación de producción (<nav>...</nav>) y pie de página (<footer>...</footer>), y su contenido proceden del componente ProductionsLayout.
  • El título Doctor Who™ Episode Database (<h1>...</h1>), la barra de navegación de episodios (<nav>...</nav>) y el elemento informativo de marca comercial (<div>...</div>) proceden del componente DoctorWhoLayout.
  • El título Episodes (<h2>...</h2>) y la lista de episodios (<ul>...</ul>) proceden del componente Episodes.
<body>
    <div id="app">
        <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>

        <h1>Doctor Who&trade; Episode Database</h1>

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

        <h2>Episodes</h2>

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

        <div>
            Doctor Who is a registered trademark of the BBC. 
            https://www.doctorwho.tv/
        </div>

        <footer>
            Footer of Productions Layout
        </footer>
    </div>
</body>

Uso compartido de un diseño de Razor Pages con componentes integrados

Si los componentes enrutables se integran en una aplicación de Razor Pages, el diseño compartido de la aplicación se puede usar con los componentes. Para obtener más información, vea Integración y representación previa de componentes Razor de ASP.NET Core.

Recursos adicionales