Создание согласованного макета на сайтах веб-страницы ASP.NET (Razor)

; автор — Том ФитцМакен (Tom FitzMacken)

В этой статье объясняется, как использовать страницы макета на веб-сайте веб-страницы ASP.NET (Razor) для создания повторно используемых блоков содержимого (например, колонтитулов) и создания единообразного оформления всех страниц на сайте.

Из этого руководства вы узнаете, как выполнять такие задачи:

  • Создание повторно используемых блоков содержимого, таких как верхние и нижние колонтитулы.
  • Как создать согласованный внешний вид для всех страниц сайта с помощью макета.
  • Передача данных во время выполнения на страницу макета.

Ниже приведены ASP.NET функции, представленные в этой статье:

  • Блоки содержимого, которые представляют собой файлы, содержащие содержимое в формате HTML для вставки на несколько страниц.
  • Страницы макета— это страницы, содержащие содержимое в формате HTML, к которому могут совместно делиться страницы веб-сайта.
  • Методы RenderPage, RenderBodyи RenderSection , которые сообщают ASP.NET, куда следует вставлять элементы страницы.
  • PageData Словарь, позволяющий обмениваться данными между блоками содержимого и страницами макета.

Версии программного обеспечения, используемые в этом руководстве

  • веб-страницы ASP.NET (Razor) 3

Это руководство также работает с веб-страницы ASP.NET 2.

Сведения о страницах макета

Многие веб-сайты содержат содержимое, отображаемое на каждой странице, например верхний и нижний колонтитулы, или поле, сообщающее пользователям, что они вошли в систему. ASP.NET позволяет создать отдельный файл с блоком содержимого, который может содержать текст, разметку и код, как и обычная веб-страница. Затем можно вставить блок содержимого на другие страницы сайта, на которых должны отображаться сведения. Таким образом, вам не придется копировать и вставлять одно и то же содержимое на каждую страницу. Создание общего содержимого, подобного этому, также упрощает обновление сайта. Если вам нужно изменить содержимое, можно просто обновить один файл, и изменения будут отражены везде, где было вставлено содержимое.

На следующей схеме показано, как работают блоки содержимого. Когда браузер запрашивает страницу с веб-сервера, ASP.NET вставляет блоки содержимого в точкеRenderPage, где вызывается метод на странице main. Затем готовая (объединенная) страница отправляется в браузер.

Концептуальная схема, показывающая, как метод RenderPage вставляет страницу, на которой указывает ссылка, в текущую страницу.

В этой процедуре вы создадите страницу, которая ссылается на два блока содержимого (верхний и нижний колонтитулы), расположенные в отдельных файлах. Эти же блоки содержимого можно использовать на любой странице сайта. Когда все будет готово, вы получите такую страницу:

Снимок экрана: страница в браузере, которая является результатом запуска страницы, включающей вызовы метода RenderPage.

  1. В корневой папке веб-сайта создайте файл с именем Index.cshtml.

  2. Замените существующую разметку следующей:

    <!DOCTYPE html>
    <html>
      <head>
        <title>Main Page</title>
      </head>
      <body>
    
        <h1>Index Page Content</h1>
        <p>This is the content of the main page.</p>
    
      </body>
    </html>
    
  3. В корневой папке создайте папку с именем Shared.

    Примечание

    Обычно файлы, совместно используемые веб-страницами, хранятся в папке с именем Общие.

  4. В папке Общие создайте файл с именем _Header.cshtml.

  5. Замените любое существующее содержимое следующим кодом:

    <div class="header">This is header text.</div>
    

    Обратите внимание, что имя файла — _Header.cshtml с символом подчеркивания (_) в качестве префикса. ASP.NET не отправляет страницу в браузер, если ее имя начинается с символа подчеркивания. Это не позволит пользователям запрашивать (непреднамеренно или иным образом) эти страницы напрямую. Рекомендуется использовать подчеркивание для имен страниц, в которых есть блоки содержимого, так как вы не хотите, чтобы пользователи могли запрашивать эти страницы— они существуют строго для вставки на другие страницы.

  6. В папке Общие создайте файл с именем _Footer.cshtml и замените содержимое следующим:

    <div class="footer">&copy; 2012 Contoso Pharmaceuticals. All rights reserved.
    </div>
    
  7. На странице Index.cshtml добавьте два вызова RenderPage метода, как показано ниже:

    <!DOCTYPE html>
    <html>
      <head>
        <title>Main Page</title>
      </head>
      <body>
    
        @RenderPage("~/Shared/_Header.cshtml")
    
        <h1>Index Page Content</h1>
        <p>This is the content of the main page.</p>
    
        @RenderPage("~/Shared/_Footer.cshtml")
    
      </body>
    </html>
    

    Здесь показано, как вставить блок содержимого на веб-страницу. Вы вызываете RenderPage метод и передаете ему имя файла, содержимое которого нужно вставить в этот момент. Здесь вы вставляете содержимое файлов _Header.cshtml и _Footer.cshtml в файл Index.cshtml .

  8. Запустите страницу Index.cshtml в браузере. (В WebMatrix в рабочей области Файлы щелкните правой кнопкой мыши файл и выберите Запустить в браузере.)

  9. В браузере просмотрите источник страницы. (Например, в интернет-Обозреватель щелкните правой кнопкой мыши страницу и выберите команду Просмотреть источник.)

    Это позволяет просматривать разметку веб-страницы, отправляемую в браузер, которая объединяет разметку страницы индекса с блоками содержимого. В следующем примере показан источник страницы, отображаемый для Index.cshtml. Вызовы, RenderPage вставленные в Файл Index.cshtml , были заменены фактическим содержимым файлов верхнего и нижнего колонтитулов.

    <!DOCTYPE html>
    <html>
      <head>
        <title>Main Page</title>
      </head>
      <body>
    
      <div class="header">
        This is header text.
      </div>
    
        <h1>Index Page Content</h1>
        <p>This is the content of the main page.</p>
    
      <div class="footer">
        &copy; 2012 Contoso Pharmaceuticals. All rights reserved.
      </div>
    
      </body>
    </html>
    

Создание согласованного внешнего вида с помощью страниц макета

Вы уже видели, что одно и то же содержимое можно легко включить на нескольких страницах. Более структурированный подход к созданию согласованного внешнего вида сайта заключается в использовании страниц макета. Страница макета определяет структуру веб-страницы, но не содержит фактического содержимого. После создания страницы макета можно создать веб-страницы, содержащие содержимое, а затем связать их со страницей макета. При отображении этих страниц они будут отформатированы в соответствии со страницей макета. (В этом смысле страница макета выступает в качестве своего рода шаблона для содержимого, определенного на других страницах.)

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

На следующей схеме показано, как страницы содержимого и страницы макета объединяются во время выполнения для создания готовой веб-страницы. Браузер запрашивает страницу содержимого. Страница содержимого содержит код, указывающий страницу макета, используемую для структуры страницы. На странице макета содержимое вставляется в точке, где RenderBody вызывается метод . Блоки содержимого также можно вставить на страницу макета, вызвав RenderPage метод , как в предыдущем разделе. Когда веб-страница будет завершена, она отправляется в браузер.

Снимок экрана: страница в браузере, которая является результатом запуска страницы, включающей вызовы метода RenderBody.

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

  1. В папке Общие на веб-сайте создайте файл с именем _Layout1.cshtml.

  2. Замените любое существующее содержимое следующим кодом:

    <!DOCTYPE html>
    <html>
      <head>
        <title>Structured Content </title>
        <link href="~/Styles/Site.css" rel="stylesheet" type="text/css" />
      </head>
      <body>
        @RenderPage("~/Shared/_Header2.cshtml")
        <div id="main">
          @RenderBody()
        </div>
        <div id="footer">
          &copy; 2012 Contoso Pharmaceuticals. All rights reserved.
        </div>
      </body>
    </html>
    

    Для вставки блоков содержимого RenderPage используется метод на странице макета. Страница макета может содержать только один вызов RenderBody метода .

  3. В папке Общие создайте файл с именем _Header2.cshtml и замените все существующее содержимое следующим:

    <div id="header">Creating a Consistent Look</div>
    
  4. В корневой папке создайте новую папку и назовите ее Стили.

  5. В папке Стили создайте файл с именем Site.css и добавьте следующие определения стилей:

    h1 {
        border-bottom: 3px solid #cc9900;
        font: 2.75em/1.75em Georgia, serif;
        color: #996600;
    }
    
    ul {
        list-style-type: none;
    }
    
    body {
        margin: 0;
        padding: 1em;
        background-color: #ffffff;
        font: 75%/1.75em "Trebuchet MS", Verdana, sans-serif;
        color: #006600;
    }
    
    #list {
        margin: 1em 0 7em -3em;
        padding: 1em 0 0 0;
        background-color: #ffffff;
        color: #996600;
        width: 25%;
        float: left;
    }
    
    #header, #footer {
        margin: 0;
        padding: 0;
        color: #996600;
    }
    

    Эти определения стилей приведены только для демонстрации того, как таблицы стилей можно использовать со страницами макета. При желании можно определить собственные стили для этих элементов.

  6. В корневой папке создайте файл с именем Content1.cshtml и замените все существующее содержимое следующим:

    @{
        Layout = "~/Shared/_Layout1.cshtml";
    }
    
    <h1> Structured Content </h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit,
    sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
    Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
    nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
    reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
    pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
    culpa qui officia deserunt mollit anim id est laborum.</p>
    

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

  7. Запустите Файл Content1.cshtml в браузере. Отображаемая страница использует формат и таблицу стилей, определенные в _Layout1.cshtml , и текст (содержимое), определенный в Content1.cshtml.

    [На снимке экрана показано выполнение CSHTML-файла content 1 в браузере.]

    Вы можете повторить шаг 6, чтобы создать дополнительные страницы содержимого, которые затем смогут совместно использовать ту же страницу макета.

    Примечание

    Вы можете настроить сайт таким образом, чтобы можно было автоматически использовать одну и ту же страницу макета для всех страниц содержимого в папке. Дополнительные сведения см. в статье Настройка поведения Site-Wide для веб-страницы ASP.NET.

Проектирование страниц макета с несколькими разделами содержимого

Страница содержимого может содержать несколько разделов, что полезно, если вы хотите использовать макеты с несколькими областями с заменяемым содержимым. На странице содержимого каждому разделу необходимо присвоить уникальное имя. (Раздел по умолчанию остается неименованным.) На странице макета добавляется метод, указывающий RenderBody , где должен отображаться неименованный раздел (по умолчанию). Затем вы добавляете отдельные RenderSection методы для отрисовки именованных разделов по отдельности.

На следующей схеме показано, как ASP.NET обрабатывает содержимое, разделенное на несколько разделов. Каждый именованный раздел содержится в блоке разделов на странице содержимого. (Они называются Header и List в примере.) Платформа вставляет раздел содержимого на страницу макета в точке RenderSection , где вызывается метод . Неименованный раздел (по умолчанию) вставляется в точке RenderBody вызова метода, как вы видели ранее.

Концептуальная схема, показывающая, как метод RenderSection вставляет разделы ссылок на текущую страницу.

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

  1. В папке Общие создайте файл с именем _Layout2.cshtml.

  2. Замените любое существующее содержимое следующим:

    <!DOCTYPE html>
    <html>
      <head>
        <title>Multisection Content</title>
        <link href="~/Styles/Site.css" rel="stylesheet" type="text/css" />
      </head>
      <body>
        <div id="header">
          @RenderSection("header")
        </div>
        <div id="list">
          @RenderSection("list")
        </div>
        <div id="main">
          @RenderBody()
        </div>
        <div id="footer">
          &copy; 2012 Contoso Pharmaceuticals. All rights reserved.
        </div>
      </body>
    </html>
    

    Метод используется RenderSection для отрисовки разделов заголовков и списков.

  3. В корневой папке создайте файл с именем Content2.cshtml и замените все существующее содержимое следующим:

    @{
        Layout = "~/Shared/_Layout2.cshtml";
    }
    
    @section header {
        <div id="header">
            Creating a Consistent Look
        </div>
    }
    
    @section list {
        <ul>
            <li>Lorem</li>
            <li>Ipsum</li>
            <li>Dolor</li>
            <li>Consecte</li>
            <li>Eiusmod</li>
            <li>Tempor</li>
            <li>Incididu</li>
        </ul>
    }
    
    <h1>Multisection Content</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit,
    sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
    Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
    nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
    reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
    pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
    culpa qui officia deserunt mollit anim id est laborum.</p>
    

    Эта страница содержимого содержит блок кода в верхней части страницы. Каждый именованный раздел содержится в блоке раздела. Остальная часть страницы содержит раздел содержимого по умолчанию (без имени).

  4. Запустите Файл Content2.cshtml в браузере.

    Снимок экрана: страница в браузере, которая является результатом запуска страницы, которая включает вызовы метода RenderSection.

Сделать разделы содержимого необязательными

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

  • Страница содержимого содержит раздел, который не имеет соответствующего раздела на странице макета.
  • Страница макета содержит раздел, для которого нет содержимого.
  • Страница макета содержит вызовы методов, которые пытаются отобразить один и тот же раздел несколько раз.

Однако это поведение можно переопределить для именованного раздела, объявив раздел необязательным на странице макета. Это позволяет определить несколько страниц содержимого, которые могут совместно использовать страницу макета, но могут содержать или не содержать содержимое для определенного раздела.

  1. Откройте Файл Content2.cshtml и удалите следующий раздел:

    @section header {
      <div id="header">
        Creating a Consistent Look
      </div>
    }
    
  2. Сохраните страницу и запустите ее в браузере. Отображается сообщение об ошибке, так как страница содержимого не предоставляет содержимое для раздела, определенного на странице макета, а именно раздела заголовка.

    Снимок экрана: ошибка, возникающая при запуске страницы, которая вызывает метод RenderSection, но соответствующий раздел не указан.

  3. В папке Общие откройте страницу _Layout2.cshtml и замените следующую строку:

    @RenderSection("header")
    

    на новый код:

    @RenderSection("header", required: false)
    

    В качестве альтернативы можно заменить предыдущую строку кода следующим блоком кода, который дает те же результаты:

    @if (IsSectionDefined("header")) {
        @RenderSection("header")
    }
    
  4. Снова запустите страницу Content2.cshtml в браузере. (Если эта страница по-прежнему открыта в браузере, ее можно просто обновить.) На этот раз страница отображается без ошибок, даже если у нее нет заголовка.

Передача данных на страницы макета

На странице содержимого могут быть определены данные, на которые необходимо ссылаться на странице макета. В этом случае необходимо передать данные со страницы содержимого на страницу макета. Например, может потребоваться отобразить состояние входа пользователя или отобразить или скрыть области содержимого на основе введенных пользователем данных.

Чтобы передать данные со страницы содержимого на страницу макета, можно поместить значения в PageData свойство страницы содержимого. Свойство PageData представляет собой коллекцию пар "имя-значение", в которой хранятся данные, которые необходимо передать между страницами. Затем на странице макета можно считывать значения из PageData свойства .

Вот еще одна схема. Здесь показано, как ASP.NET могут использовать PageData свойство для передачи значений со страницы содержимого на страницу макета. Когда ASP.NET начинает создавать веб-страницу, она создает коллекцию PageData . На странице содержимого вы пишете код для добавления данных в коллекцию PageData . К значениям PageData в коллекции также могут обращаться другие разделы на странице содержимого или дополнительные блоки содержимого.

Концептуальная схема, показывающая, как страница содержимого может заполнить словарь PageData и передать эти сведения на страницу макета.

В следующей процедуре показано, как передать данные со страницы содержимого на страницу макета. При запуске страницы отображается кнопка, которая позволяет пользователю скрыть или отобразить список, определенный на странице макета. Когда пользователи нажимают кнопку, в свойстве PageData задается значение true/false (логическое значение). Страница макета считывает это значение и, если оно имеет значение false, скрывает список. Значение также используется на странице содержимого, чтобы определить, следует ли отображать кнопку Скрыть список или Показать список .

[Снимок экрана: страница

  1. В корневой папке создайте файл с именем Content3.cshtml и замените все существующее содержимое следующим:

    @{
        Layout = "~/Shared/_Layout3.cshtml";
    
        PageData["Title"] = "Passing Data";
        PageData["ShowList"] = true;
    
        if (IsPost) {
            if (Request.Form["list"] == "off") {
                PageData["ShowList"] = false;
            }
        }
    }
    
    @section header {
      <div id="header">
        Creating a Consistent Look
      </div>
    }
    
    <h1>@PageData["Title"]</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit,
    sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
    Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
    nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
    reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
    pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
    culpa qui officia deserunt mollit anim id est laborum.</p>
    
    @if (PageData["ShowList"] == true) {
        <form method="post" action="">
          <input type="hidden" name="list" value="off" />
          <input type="submit" value="Hide List" />
        </form>
    }
    else {
        <form method="post" action="">
          <input type="hidden" name="list" value="on" />
          <input type="submit" value="Show List" />
        </form>
    }
    

    Код сохраняет два фрагмента данных в свойстве PageData — заголовок веб-страницы и значение true или false, чтобы указать, следует ли отображать список.

    Обратите внимание, что ASP.NET позволяет поместить разметку HTML на страницу условно с помощью блока кода. Например, блок в теле страницы определяет, какая форма будет отображаться в зависимости от того, if/else задано ли PageData["ShowList"] значение true.

  2. В папке Общие создайте файл с именем _Layout3.cshtml и замените все существующее содержимое следующим:

    <!DOCTYPE html>
    <html>
      <head>
        <title>@PageData["Title"]</title>
        <link href="~/Styles/Site.css" rel="stylesheet" type="text/css" />
      </head>
      <body>
        <div id="header">
          @RenderSection("header")
        </div>
          @if (PageData["ShowList"] == true) {
              <div id="list">
                @RenderPage("~/Shared/_List.cshtml")
              </div>
          }
        <div id="main">
          @RenderBody()
        </div>
        <div id="footer">
          <p>&copy; 2012 Contoso Pharmaceuticals. All rights reserved.</p>
        </div>
      </body>
    </html>
    

    Страница макета содержит выражение в элементе <title> , которое получает значение заголовка PageData из свойства . Он также использует ShowList значение свойства , PageData чтобы определить, следует ли отображать блок содержимого списка.

  3. В папке Общие создайте файл с именем _List.cshtml и замените все существующее содержимое следующим:

    <ul>
      <li>Lorem</li>
      <li>Ipsum</li>
      <li>Dolor</li>
      <li>Consecte</li>
      <li>Eiusmod</li>
      <li>Tempor</li>
      <li>Incididu</li>
    </ul>
    
  4. Запустите страницу Content3.cshtml в браузере. Страница отображается со списком в левой части страницы и кнопкой Скрыть список в нижней части.

    Снимок экрана: страница со списком и кнопкой

  5. Щелкните Скрыть список. Список исчезнет, а кнопка изменится на Показать список.

    Снимок экрана: страница без списка и кнопка

  6. Нажмите кнопку Показать список , и список снова отобразится.

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

Настройка поведения Site-Wide для веб-страницы ASP.NET