Diseños de ASP.NET Core Blazor

Nota

Esta no es la versión más reciente de este artículo. Para la versión actual, consulte la versión .NET 8 de este artículo.

Importante

Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.

Para la versión actual, consulte la versión .NET 8 de este artículo.

En este artículo se explica cómo crear componentes de diseño reutilizables para aplicaciones Blazor.

Utilidad de los diseños de 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, normalmente se colocan en la carpeta Shared o Layout 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.

Nota

Para obtener más información sobre RenderFragment, consulte Componentes de Razor de ASP.NET Core.

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>).

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 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. El diseño de Blazor adopta Flexbox layout model (MDN documentation) (especificación de W3C).

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, MainLayout.razor.css. La implementación del marco ASP.NET Core de la hoja de estilos está disponible para su inspección en el origen de referencia de ASP.NET Core (repositorio dotnet/aspnetcore de GitHub):

Nota:

Los vínculos de la documentación al origen de referencia de .NET cargan normalmente la rama predeterminada del repositorio, que representa el desarrollo actual para la próxima versión de .NET. Para seleccionar una etiqueta de una versión específica, use la lista desplegable Cambiar ramas o etiquetas. Para obtener más información, vea Procedimientos para seleccionar una etiqueta de versión de código fuente de ASP.NET Core (dotnet/AspNetCore.Docs #26205).

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, MainLayout.razor.css. La implementación del marco ASP.NET Core de la hoja de estilos está disponible para su inspección en el origen de referencia de ASP.NET Core (repositorio dotnet/aspnetcore de GitHub):

Nota

Los vínculos de la documentación al origen de referencia de .NET cargan normalmente la rama predeterminada del repositorio, que representa el desarrollo actual para la próxima versión de .NET. Para seleccionar una etiqueta de una versión específica, use la lista desplegable Cambiar ramas o etiquetas. Para obtener más información, vea Procedimientos para seleccionar una etiqueta de versión de código fuente de ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Aplicación de un diseño

Hacer que el espacio de nombres de diseño esté disponible

Las ubicaciones de los archivos de diseño y los espacios de nombres cambiaron con el tiempo para el marco Blazor. Según la versión de Blazor y el tipo de aplicación Blazor que esté compilando, es posible que tenga que indicar el espacio de nombres del diseño al usarlo. Al hacer referencia a una implementación de diseño y no se encuentre el diseño sin indicar el espacio de nombres del diseño, use cualquiera de los métodos siguientes:

  • Agregue una directiva @using al archivo _Imports.razor para la ubicación de los diseños. En el ejemplo siguiente, una carpeta de diseños con el nombre Layout está dentro de una carpeta Components y el espacio de nombres de la aplicación es BlazorSample:

    @using BlazorSample.Components.Layout
    
  • Agregue una directiva @using en la parte superior de la definición del componente donde se usa el diseño:

    @using BlazorSample.Components.Layout
    @layout DoctorWhoLayout
    
  • Califique completamente el espacio de nombres del diseño donde se usa:

    @layout BlazorSample.Components.Layout.DoctorWhoLayout
    

Aplicación de diseño a un componente

Use la directiva @layoutRazor 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.

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>

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 "database" H1 (<h1>...</h1>) del encabezado (<header>...</header>), la barra de navegación (<nav>...</nav>) y la información de marca comercial del pie de página (<footer>...</footer>) proceden del componente DoctorWhoLayout.
  • El título "episodes" H2 (<h2>...</h2>) y la lista de episodios (<ul>...</ul>) proceden del componente Episodes.
<header>
    <h1 ...>...</h1>
</header>

<nav>
    ...
</nav>

<h2>...</h2>

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

<footer>
    ...
</footer>

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 Razor@layout al archivo raíz _Imports.razor, pues 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 @layoutRazor ú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 RouteView del componente Router. Use el parámetro DefaultLayout para establecer el tipo de diseño:

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

En el ejemplo anterior, el marcador de posición {LAYOUT} es el diseño (por ejemplo, DoctorWhoLayout si el nombre de archivo del diseño es DoctorWhoLayout.razor). Es posible que tenga que identificar el espacio de nombres del diseño en función de la versión de .NET y el tipo de aplicación Blazor. Para obtener más información, consulte la sección Hacer que el espacio de nombres de diseño esté disponible.

Especificar el diseño como un diseño predeterminado en el RouteView del 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>).

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

Es posible que tenga que identificar el espacio de nombres del diseño en función de la versión de .NET y el tipo de aplicación Blazor. Para obtener más información, consulte la sección Hacer que el espacio de nombres de diseño esté disponible.

Importante

Blazor Web Apps no usa el parámetro NotFound (marcado <NotFound>...</NotFound>), pero el parámetro es compatible con versiones anteriores para evitar un cambio importante en el marco. La canalización de middleware del lado servidor ASP.NET procesa las solicitudes en el servidor. Use técnicas del lado servidor para controlar las solicitudes incorrectas. Para obtener más información, vea Modos de representación de ASP.NET CoreBlazor.

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, vea 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.

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/";
}

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.

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>

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 "database" H1 (<h1>...</h1>), la barra de navegación de episodios (<nav>...</nav>) y la información de marca comercial (<div>...</div>) proceden del componente de DoctorWhoLayout.
  • El título "episodes" H2 (<h2>...</h2>) y la lista de episodios (<ul>...</ul>) proceden del 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>

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 más información, consulte Integrar componentes ASP.NET Core Razor en aplicaciones ASP.NET Core.

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 más información, vea Integración y representación previa de componentes Razor de ASP.NET Core.

Secciones

Para controlar el contenido de un diseño desde un componente Razor secundario, consulte las secciones ASP.NET Core de Blazor.

Recursos adicionales