Макеты Blazor в ASP.NET Core

Примечание.

Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 8 этой статьи.

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В текущем выпуске см . версию .NET 8 этой статьи.

В этой статье вы узнаете, как создавать многократно используемые компоненты макета для приложений Blazor.

Полезность макетов Blazor

Некоторые элементы приложения, такие как меню, сообщения об авторских правах и логотипы компании, обычно являются частью общей презентации приложения. Размещение копии разметки для этих элементов во всех компонентах приложения не эффективно. При каждом обновлении одного из этих элементов необходимо обновить каждый компонент, использующий этот элемент. Этот подход предусматривает дорогостоящее обслуживание и может привести к несогласованности содержимого при отсутствии обновления. Макеты решают эти проблемы.

Макет Blazor — это компонент Razor, который совместно использует разметку с компонентами, ссылающимися на нее. Макеты могут использовать привязку данных, внедрение зависимостей и другие возможности компонентов.

Компоненты макета

Создание компонента макета

Чтобы создать компонент макета, сделайте следующее:

  • Создайте компонент Razor, определенный шаблоном Razor или кодом C#. Компоненты макета, основанные на шаблоне Razor, используют расширение файла .razor так же, как и обычные компоненты Razor. Так как компоненты макета совместно используются для компонентов приложения, они обычно размещаются в приложении Shared или Layout папке. Однако макеты можно разместить в любом расположении, доступном для компонентов, которые его используют. Например, макет можно поместить в ту же папку, в которой находятся компоненты, использующие ее.
  • Создайте компонент, производный от LayoutComponentBase. LayoutComponentBase определяет свойство Body (тип RenderFragment) для отображаемого содержимого внутри макета.
  • Использует синтаксис @BodyRazor для указания расположения в разметке макета, в которой отображается содержимое.

Примечание.

Дополнительные сведения о RenderFragment см. в статье Компоненты Razor ASP.NET Core.

В следующем компоненте показан шаблон DoctorWhoLayout компонента макета Razor. Макет наследует LayoutComponentBase и задает @Body между панелью навигации (<nav>...</nav>) и нижним колонтитулом (<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/";
}

Компонент MainLayout

В приложении, созданном из шаблона проекта Blazor, компонент MainLayout является макетом приложения по умолчанию. BlazorМакет принимает Flexbox layout model (MDN documentation)спецификацию W3C.

Возможность изоляции CSS Blazor предусматривает применение изолированных стилей CSS к компоненту MainLayout. По соглашению стили предоставляются сопутствующей таблицей стилей с тем же именем, MainLayout.razor.css. Реализация таблицы стилей ASP.NET Core доступна для проверки в источнике ссылок ASP.NET Core (dotnet/aspnetcore репозиторий GitHub):

Примечание.

По ссылкам в документации на справочные материалы по .NET обычно загружается ветвь репозитория по умолчанию, которая представляет текущую разработку для следующего выпуска .NET. Чтобы выбрать тег для определенного выпуска, используйте раскрывающийся список Switch branches or tags (Переключение ветвей или тегов). Дополнительные сведения см. в статье Выбор тега версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Возможность изоляции CSS Blazor предусматривает применение изолированных стилей CSS к компоненту MainLayout. По соглашению стили предоставляются сопутствующей таблицей стилей с тем же именем, MainLayout.razor.css. Реализация таблицы стилей ASP.NET Core доступна для проверки в источнике ссылок ASP.NET Core (dotnet/aspnetcore репозиторий GitHub):

Примечание.

По ссылкам в документации на справочные материалы по .NET обычно загружается ветвь репозитория по умолчанию, которая представляет текущую разработку для следующего выпуска .NET. Чтобы выбрать тег для определенного выпуска, используйте раскрывающийся список Switch branches or tags (Переключение ветвей или тегов). Дополнительные сведения см. в статье Выбор тега версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Применение макета

Сделать пространство имен макета доступным

Расположения файлов макета и пространства имен изменились со временем для Blazor платформы. В зависимости от версии и типа создаваемого Blazor приложения может потребоваться указать пространство имен макета Blazor при его использовании. При ссылке на реализацию макета и макет не найден, не указывая пространство имен макета, выполните любой из следующих подходов:

  • Добавьте директиву @using в _Imports.razor файл для расположения макетов. В следующем примере папка макетов с именем Layout находится в папкеComponents, а пространство имен приложения :BlazorSample

    @using BlazorSample.Components.Layout
    
  • @using Добавьте директиву в верхней части определения компонента, где используется макет:

    @using BlazorSample.Components.Layout
    @layout DoctorWhoLayout
    
  • Полное определение пространства имен макета, в котором оно используется:

    @layout BlazorSample.Components.Layout.DoctorWhoLayout
    

Применение макета к компоненту

@layoutRazor Используйте директиву для применения макета к маршрутизируемому Razor компоненту, который имеет директиву@page. Компилятор преобразует @layout в LayoutAttribute и применяет атрибут к классу компонента.

Содержимое следующего компонента Episodes вставляется в DoctorWhoLayout в позиции @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>

Следующая отображаемая HTML-разметка создается предыдущим компонентом DoctorWhoLayout и компонентом Episodes. Остальная часть разметки не показана, чтобы заострить внимание на содержимом, предоставленном двумя рассматриваемыми компонентами:

  • Заголовок H1 "database" (<h1>...</h1>) в заголовке (), панель навигации (<header>...</header><nav>...</nav>) и сведения о товарных знаках в нижнем DoctorWhoLayout колонтитуле (<footer>...</footer>) приходят из компонента.
  • Заголовок H2 "эпизоды" (<h2>...</h2>) и список эпизодов (<ul>...</ul>) приходят из Episodes компонента.
<header>
    <h1 ...>...</h1>
</header>

<nav>
    ...
</nav>

<h2>...</h2>

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

<footer>
    ...
</footer>

При указании макета непосредственно в компоненте переопределяется макет по умолчанию:

Применение макета к папке компонентов

В каждой папке приложения может дополнительно содержаться файл шаблона с именем _Imports.razor. Компилятор включает директивы, указанные в файле импорта, во все шаблоны Razor в одной и той же папке и рекурсивно во всех ее вложенных папках. Таким образом, файл _Imports.razor, содержащий @layout DoctorWhoLayout, обеспечивает использование компонента DoctorWhoLayout всеми компонентами в папке. Нет необходимости многократно добавлять @layout DoctorWhoLayout во все компоненты Razor (.razor) в папке и вложенных папках.

_Imports.razor:

@layout DoctorWhoLayout
...

Файл _Imports.razor аналогичен файлу _ViewImports.cshtml для представлений и страниц Razor, однако он применяется специально к файлам компонентов Razor.

При указании макета в _Imports.razor переопределяется макет, заданный как макет приложения по умолчанию маршрутизатора, который описан в следующем разделе.

Предупреждение

Не добавляйте директиву Razor@layout в корневой файл _Imports.razor, так как это приведет к созданию бесконечного цикла макетов. Чтобы управлять макетом приложения по умолчанию, укажите макет в компоненте Router. Дополнительные сведения см. в следующем разделе Применение макета по умолчанию к приложению.

Примечание.

Директива @layoutRazor применяет только макет к маршрутизируемым Razor компонентам с директивой @page .

Применение макета по умолчанию к приложению

Укажите макет приложения по умолчанию в компоненте RouteView компонента Router. DefaultLayout Используйте параметр, чтобы задать тип макета:

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

В предыдущем примере заполнитель — это макет (например, {LAYOUT}DoctorWhoLayout если имя файла макета равно DoctorWhoLayout.razor). Возможно, потребуется использовать пространство имен макета Blazor в зависимости от версии и типа приложения .NET. Дополнительные сведения см. в разделе "Сделать пространство имен макета доступным ".

Указание макета в качестве макета по умолчанию в Router компоненте RouteView является полезной практикой, так как можно переопределить макет на основе каждого компонента или для каждой папки, как описано в предыдущих разделах этой статьи. Мы рекомендуем задать макет приложения по умолчанию с помощью компонента Router, так как это самый распространенный и гибкий подход к использованию макетов.

Применение макета к произвольному содержимому (компонент LayoutView)

Чтобы задать макет для шаблона произвольного содержимого Razor, укажите макет с помощью компонента LayoutView. Можно использовать LayoutView в любом компоненте Razor. В следующем примере для компонента макета с именем ErrorLayout задается шаблон NotFound компонента 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>

Может потребоваться определить пространство имен макета Blazor в зависимости от версии и типа приложения .NET. Дополнительные сведения см. в разделе "Сделать пространство имен макета доступным ".

Внимание

Blazorвеб-приложения не используйте NotFound параметр (<NotFound>...</NotFound>разметку), но параметр поддерживается для обратной совместимости, чтобы избежать критического изменения в платформе. Серверная ASP.NET конвейер по промежуточному по промежуточному слоя Core обрабатывает запросы на сервере. Используйте методы на стороне сервера для обработки плохих запросов. Дополнительные сведения см. в режимах отрисовки ASP.NET CoreBlazor.

Примечание.

В выпуске ASP.NET Core 5.0.1 и дальнейших выпусках 5.x компонент Router содержит параметр PreferExactMatches со значением @true. Дополнительные сведения см. в статье Миграция с ASP.NET Core 3.1 на 5.0.

Вложенные макеты

Компонент может ссылаться на макет, который, в свою очередь, ссылается на другой макет. Например, для создания структур многоуровневого меню используются вложенные макеты.

В следующем примере показано использование вложенных макетов. Компонент Episodes, показанный в разделе Применение макета к компоненту, является отображаемым компонентом. Компонент ссылается на компонент DoctorWhoLayout.

Следующий компонент DoctorWhoLayout является измененной версией примера, показанного ранее в этой статье. Элементы верхнего и нижнего колонтитула удалены, а макет ссылается на другой макет — ProductionsLayout. Компонент Episodes отображается там, где находится @Body в 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/";
}

Компонент ProductionsLayout содержит элементы макета верхнего уровня, где теперь находятся элементы верхнего (<header>...</header>) и нижнего (<footer>...</footer>) колонтитулов. Компонент DoctorWhoLayout с компонентом Episodes отображается там, где находится @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>

Следующая отображаемая HTML-разметка создается с помощью предыдущего вложенного макета. Остальная часть разметки не показана, чтобы заострить внимание на вложенном содержимом, предоставленном тремя рассматриваемыми компонентами:

  • Элементы заголовка (<header>...</header>), рабочей панели навигации (<nav>...</nav>) и нижнего колонтитула (<footer>...</footer>) и их содержимое взяты из компонента ProductionsLayout.
  • Заголовок H1 "database" (), панель навигации эпизодов (<h1>...</h1><nav>...</nav>) и сведения о товарных знаках (<div>...</div>) приходят из DoctorWhoLayout компонента.
  • Заголовок H2 "эпизоды" (<h2>...</h2>) и список эпизодов (<ul>...</ul>) приходят из 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>

Совместное использование макета Razor Pages с интегрированными компонентами

Если маршрутизируемые компоненты интегрированы в приложение Razor Pages, общий макет приложения можно использовать с компонентами. Дополнительные сведения см. в разделе "Интеграция компонентов ASP.NET Core Razor " в приложения ASP.NET Core.

Если маршрутизируемые компоненты интегрированы в приложение Razor Pages, общий макет приложения можно использовать с компонентами. Дополнительные сведения см. в статье Компоненты Razor для предварительной визуализации и интеграции ASP.NET Core.

Разделы

Сведения об управлении содержимым в макете из дочернего Razor компонента см. в разделах ASP.NET CoreBlazor.

Дополнительные ресурсы