Поделиться через


Макеты ASP.NET Core Blazor

Примечание.

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

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

Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущей версии см. версию этой статьи для .NET 9.

Внимание

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

В текущей версии см. версию этой статьи для .NET 9.

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

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

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

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

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

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

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

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

Примечание.

Дополнительные сведения о 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

<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 соответствует спецификации W3C.

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

Примечание.

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

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

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

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

Расположения файлов макета и пространства имен изменялись со временем для фреймворка 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>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>) и сведения о товарных знаках в нижнем колонтитуле (<footer>...</footer>) берутся из компонента DoctorWhoLayout.
  • Заголовок 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. Дополнительные сведения см. в следующем разделе Применение макета по умолчанию к приложению.

То же условие приводит к использованию файла _Imports.razor для применения макета к папке компонентов с директивой @layout, а сам компонент макета находится в той же папке или иерархии папок _Imports.razor файла. Бесконечный цикл применения макета происходит, так как директива @layout также применяется к компоненту макета. Чтобы избежать проблем рекурсии, рекомендуется хранить элементы макета в отдельной папке (например, Layouts), отдельно от тех мест, где они применяются в файлах _Imports.razor.

Примечание.

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

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

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

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

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

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

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

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

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

Внимание

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

Примечание.

В выпуске 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

<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>
@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 с MVC или Razor Страницами для получения дополнительной информации.

Разделы

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

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