Blazor позволяют выполнять привязку значения полей и свойств компонентов к атрибутам элементов HTML. Для этого у элементов HTML применяется атрибут @bind-
Стоит отметить, что поскольку под капотом задействуются события и интерактивность, то приложение должно поддерживать интерактивный рендеринг на сервере или на клиенте. В данном случае используем интерактивный рендеринг на сервере.
Например, пусть у нас в проекте есть два компонента: корневой компонент App.razor и Home.razor:
На корневом компоненте App.razor загружается вложенный компонент Home:
@page "/" <!DOCTYPE html> <html> <head> <title>METANIT.COM</title> <meta charset="utf-8" /> </head> <body> <Home /> <script src="_framework/blazor.web.js"></script> </body> </html>
Привязку данных можно выполнить к любому атрибуту элемента html. Например, у элемента ввода input есть атрибут value, который
представляет введенное в элемент значение. Для привязки к этому атрибуту значения применяется атрибут @bind-value
(то есть @bind-[название_атрибута]
).
Например, определим в компоненте Home.razor следующий код:
@using Microsoft.AspNetCore.Components.Web @rendermode RenderMode.InteractiveServer <div> <input @bind-value="@item" /> <p>Value: @item</p> </div> @code { string item = "hello"; }
Здесь текстовое поле input посредством атрибута @bind-value привязано к значению переменной item.
При рендеринге компонента элемент input получает значение переменной item. После того, как пользователь введет в это текстовое поле
новое значение и переместит фокус на другой элемент веб-страницы, сработает событие onchange
, и значение переменной item
будет обновлено.
То есть фактически данный код будет эквивалентен следующему:
@using Microsoft.AspNetCore.Components.Web @rendermode RenderMode.InteractiveServer <div> <input value="@item" @onchange="@((ChangeEventArgs e) => item = e.Value.ToString())" /> <p>Value: @item</p> </div> @code { string item = "hello"; }
То есть в обработчике события onchange меняется переменной item присваивается новое введенное значение. Однако благодаря атрибуту @bind нам не надо прописывать дополнительно всю эту логику, blazor делает за нас все сам.
Для проверки значение item дополнительно выводится в параграф под текстовым полем:
Для элементов ввода input вместо атрибута @bind-value
можно использовать его сокращенную версию - @bind:
@using Microsoft.AspNetCore.Components.Web @rendermode RenderMode.InteractiveServer <div> <input type="text" @bind="@item" /> <p>Value: @item</p> </div> @code { string item = "hello"; }
С помощью атрибута @bind-атрибут:event у элементов HTML можно назначить другое событие, которое будет
изменять привязанное к элементу значение. По умолчанию за это отвечает событие onchange
, которое срабатывает, когда элемент ввода теряет
фокус. Так, в примере выше, чтобы после ввода нового значения в текстовое поле изменилось значение переменной item, необходимо было убирать фокус с элемента ввода.
Это может быть неудобно. Допустим, мы хотим сразу изменять значение. Для этого используем для обработки изменения значения событие oninput:
@using Microsoft.AspNetCore.Components.Web @rendermode RenderMode.InteractiveServer <div> <input @bind-value="@item" @bind-value:event="oninput" /> <p>Value: @item</p> </div> @code { string item = "hello"; }
Событие oninput
срабатывает сразу, как происходит изменение значения в текстовом поле. То есть теперь не потребуется убирать фокус.
Опять же если привязка идет к атрибуту value, то вместо @bind-value:event
можно использовать @bind:event
:
@using Microsoft.AspNetCore.Components.Web @rendermode RenderMode.InteractiveServer <div> <input @bind="@item" @bind:event="oninput" /> <p>Value: @item</p> </div> @code { string item = "hello"; }
Выше рассматривалась привязка на примере атрибута value полей input. Но подобным образом можно выполнять привязку и к другим атрибутам. Они работают по тому принципу. Например, выполним привязку к атрибуту style элемента div:
@using Microsoft.AspNetCore.Components.Web @rendermode RenderMode.InteractiveServer <p> <input @bind-value="divStyle" @bind-value:event="oninput" style="width:300px;" /> </p> <div style="@divStyle"></div> @code { string divStyle = "background-color:blue;width:100px;height:100px;"; }
В данном случае идет привязка атрибута style к переменной divStyle, значение которой изменяется в поле ввода
Выше в первом примере при вводе значения в текстовое поле при использовании события onchange необходимо было убирать фокус с поля, чтобы привязанное значение изменилось. В то же время при использовании события oninput убирать фокус с элемента не надо, при нажатии клавиши клавиатуры тут же будет изменяться привязанное значение. Вследствие этого может показаться, что лучше использовать событии oninput. Однако в реальности oninput может отрицателным образом сказаться на возможности ввода. Например, возьмем следующий компонент:
@using Microsoft.AspNetCore.Components.Web @rendermode RenderMode.InteractiveServer <div> <input @bind-value="number" @bind-value:event="oninput" /> <p>@number</p> </div> @code { double number = 23.8; }
Здесь к текстовому полю привязана переменная типа double, которая допускает использование точки или запятой (в зависимости от текущей культуры) для разделения целой и дробной части. Если при вводе мы уберем разделитель целой и дробной части (точку/запятую), оставив только целую часть, и впоследствии попытаемся его ввести после цифровых символов, то мы не сможем это сделать. Так как при событии oninput при каждом нажатии клавиши клавиатуры будет изменятся введенное значение. Введенный символ точки/запятой не сможет быть распарсен и поэтому будет отброшен. Мы сможем ввести только все число полностью.
Поэтому в целом рекомендуется использовать onchange, чтобы избежать проблем с парсингом значений.
Чтобы выполнить после установки значения некоторую асинхронную обработку, применяется атрибут @bind:after, которому передается выполняемое действие:
@bind:after="действие"
Выполняемое действие должно возвращать объект Action или Task и выполняется после того, как установлено привязанное значение. Рассмотрим небольшой пример:
@using Microsoft.AspNetCore.Components.Web @rendermode RenderMode.InteractiveServer <input @bind="searchText" @bind:after="PerformSearch" /> <ul> @foreach(var item in found) { <li>@item</li> } </ul> @code { // условная база данных List<string> items = []; // найденные данные List<string> found = []; // ключ поиска string searchText = ""; async Task PerformSearch() { // для имитации долгой работы await Task.Delay(400); found = items.Where(item => item.Contains(searchText)).ToList(); } }
Здесь поле ввода привязано к переменной searchText
. После изменения ее значения выполняется асинхронный метод PeformSearch. В данном случае мы делаем
условный запрос к базе данных, в роли которой выступает список items. И выбираем из него все элементы, которые содержат текст из searchText. Найденные значения помещаются в список found,
который выводится на страницу. Для имитации долгой работы используется задержка в 400 миллисекунд.
Атрибут @bind:after
можно применять, когда надо выполнить некоторую постобработку, в частности, выполнение сетевого запроса, обращение к базе данных. Причем эти действия необязательно
должны быть асинхронными методами. Например, в примере выше можно было бы определить метод PeformSearch следующим образом:
void PerformSearch() { found = items.Where(item => item.Contains(searchText)).ToList(); }