Компоненты могут содержать другие компоненты. Работа приложения Blazor начинается с выполнения главного компонента, который, в свою очередь, содержит остальные компоненты. В прошлой теме был рассмотрен добавление и рендеринг главного компонента приложения. Однако добавление дочерних компонентов отличается - для добавления дочернего компонента используется тег, назначение которого совпадает с названием компонента. Например, определим в проекте для неглавных компонентов папку Components. И добавим в нее новый компонент - Home.razor:
Определим в компоненте Home.razor:
<h2>@header</h2> @code{ string header = "Главная страница"; }
Вызовем этот компонент в главном компоненте App.razor:
@page "/" <!DOCTYPE html> <html> <head> <title>METANIT.COM</title> <meta charset="utf-8" /> </head> <body> <h1>@header</h1> <Home /> </body> </html> @code { string header = "Приложение Blazor"; }
Для добавления компонента Home определяем его как обычный html-элемент:
<Home />
Вместо сокращенной записи можно явным образом определить открывающий и закрывающий теги элемента:
<Home></Home>
Таким образом, компонент App в данном случае является родительским и содержит дочерний компонент Home.
Компоненты существуют независимо друг от друга. Переменные и методы одного компонента применяются только в рамках этого компонента. Например, в примеры выше оба компонента определяли свою собственную переменную header. Тем не менее существует возможность передачи данных из родительского компонента в дочерний. Эту возможность предоставляют параметры компонента - публичные свойства компонента, к которым применяется атрибут Parameter. Например, изменим компонент Home.razor:
<h2>@Title</h2> @code { [Parameter] public string Title { get; set; } = "Default Title"; }
Теперь компонент содержит одно свойство Title, к которому применяется атрибут [Parameter]
, поэтому это свойство можно назвать параметром компонента.
Через это свойства компонент может получить извне некоторые данные.
Следует учитывать, что подобные свойства-параметры должны представлять автосвойства, у которых блоки set и get не содержат никакой логики.
Далее изменим вызов компонента Home в родительском компоненте App:
@page "/" <!DOCTYPE html> <html> <head> <title>METANIT.COM</title> <meta charset="utf-8" /> </head> <body> <h1>Hello Blazor</h1> <Home Title="Home Page" /> <Home Title="@someTitle" /> <Home /> </body> </html> @code { string someTitle = "Main Page"; }
Здесь определяется три вложенных компонента Home. Через атрибуты, названия которых совпадают с названиями параметров компонента, можно передать этим параметрам некоторые данные. Причем можно передать параметру компонента значение некоторого выражения, например, переменной, как в случае со вторым вызовом Home. Если не передать значения, то свойства компонента получат значения по умолчанию.
Причем можно передавать более сложное содержимое, нежели простые строки. Например, пусть Home.razor принимает список строк:
<h2>Количество пользователей: @Count</h2> <ul> @foreach(var user in Users) { <li>@user</li> } </ul> @code{ [Parameter] public List<string> Users { get; set; } = new(); [Parameter] public int Count { get; set; } }
Теперь компонент получает список и выводит его в коде html. Передадим этот список в родительском компоненте App:
@page "/" <h1>Приложение Blazor</h1> <Home Count="@users.Count" Users="@users"></Home> @code{ List<string> users = new List<string> { "Tom", "Bob", "Sam", "Mike" }; }
По умолчанию если свойствам-параметрам не передано значение, то они получают значение по умолчанию. Но иногда требуется, чтобы параметрам-свойствам извне обязательно передавалось некоторое значение. В этом случае можно использовать атрибут [EditorRequired]:
<h2>@Title</h2> @code { [Parameter] [EditorRequired] public string Title { get; set; } = ""; }
В этом случае, если не передать значение параметру Title, ошибки не произойдет. Однако на уровне статического анализатора кода в Visual Studio мы получим предупреждение, что значение необходимо передать:
Если надо передать несколько различных значений, то мы можем для всех этих значений определить соответствующие свойства-параметра. Например, код Home.razor:
<ul> <li>Name: @Name</li> <li>Age: @Age</li> <li>IsMarried: @IsMarried</li> </ul> @code { [Parameter] public string Name { get; set; } = ""; [Parameter] public int Age { get; set; } [Parameter] public bool IsMarried { get; set; } }
И в компоненте App мы можем передать этим свойствам какие-нибудь значения:
@page "/" <Home Name="Tom" Age="38" IsMarried="false" />
В качестве альтернативы можно сгруппировать все значения через кортеж. Так, изменим компонент Home следуюшим образом:
<ul> <li>Name: @Data?.Item1</li> <li>Age: @Data?.Item2</li> <li>IsMarried: @Data?.Item3</li> </ul> @code { [Parameter] public Tuple<string, int, bool>? Data { get; set; } }
А в компоненте App передать значения в Home:
@page "/" <Home Data="@data" /> @code { Tuple<string, int, bool> data = new("Tom", 38, false); }
С помощью свойства ChildContent в дочерний компонент можно передать из родительского некоторое содержимое. Например, изменим компонент Home.razor следующим образом:
<h2>@Title</h2> <div>@ChildContent</div> <hr /> <div>Условный футер</div> @code{ [Parameter] public string Title { get; set; } = ""; [Parameter] public RenderFragment? ChildContent { get; set; } }
Согласно условностям свойство должно называться именно ChildContent
, и оно должно представлять тип
RenderFragment. В остальном оно используется аналогично другим свойствам. Например, его содержимое можно вывести на веб-страницу
где-нибудь в разметке компонента.
Теперь изменим родительский компонент App:
@page "/" <h1>Приложение Blazor</h1> <Home Title="Главная страница"> Случайное содержимое дочернего компонента </Home>
Все то, что передается между открывающим и закрывающим тегами <Home>
и </Home>
и будет представлять
свойство ChildContent
дочернего компонента
Передаваемое содержимое может быть и более сложным, нежели простая строка. Например, можно передать код html. Так, изменим родительский компонент App.razor:
@page "/" <h1>Приложение Blazor</h1> <Home Title="Главная страница"> <div> <h3>Отрывок</h3> <p>Высокой страсти не имея</p> <p>Для кода жизни не щадить,</p> <p>Не мог он джаву от сишарпа</p> <p>Как мы ни бились, отличить.</p> </div> </Home>