Hầu hết các phần tử HTML hiển thị các sự kiện được kích hoạt khi điều gì đó quan trọng xảy ra, chẳng hạn như trang đã tải xong, người dùng đã nhấp vào nút hoặc nội dung của phần tử HTML đã thay đổi. Một ứng dụng có thể xử lý một sự kiện theo một số cách:
- Ứng dụng có thể bỏ qua sự kiện.
- Ứng dụng có thể chạy trình xử lý sự kiện được viết bằng JavaScript để xử lý sự kiện.
- Ứng dụng có thể chạy trình xử lý sự kiện Blazor được viết bằng C # để xử lý sự kiện.
Trong bài này, bạn sẽ xem xét chi tiết tùy chọn thứ ba; cách tạo trình xử lý sự kiện Blazor trong C# để xử lý một sự kiện.
Xử lý sự kiện với Blazor và C#
Mỗi phần tử trong HTML của ứng dụng Blazor hỗ trợ nhiều sự kiện. Hầu hết các sự kiện này tương ứng với các sự kiện DOM có sẵn trong các ứng dụng web thông thường, nhưng bạn cũng có thể tạo các sự kiện do người dùng xác định được kích hoạt bằng cách viết mã.
Để nắm bắt một sự kiện với Blazor, bạn viết một phương thức C # để xử lý sự kiện, sau đó liên kết sự kiện với phương thức bằng một chỉ thị Blazor. Đối với sự kiện DOM, lệnh Blazor có cùng tên với sự kiện HTML tương đương, chẳng hạn như @onkeydown hoặc @onfocus.
Ví dụ: ứng dụng mẫu được tạo bằng cách sử dụng Ứng dụng máy chủ Blazor chứa mã được hiển thị bên dưới trên trang Counter.razor. Trang này hiển thị một nút. Khi người dùng chọn nút, sự kiện @onclick sẽ kích hoạt phương thức IncrementCount làm tăng bộ đếm cho biết số lần nút đã được nhấp. Giá trị của biến bộ đếm được hiển thị bởi phần tử <p> trên trang:
@page "/counter" <h1>Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } }
Nhiều phương thức xử lý sự kiện nhận một tham số cung cấp thêm thông tin theo ngữ cảnh. Tham số này được gọi là tham số EventArgs. Ví dụ: sự kiện @onclick chuyển thông tin về nút mà người dùng đã nhấp hoặc liệu họ có nhấn một nút như Ctrl hoặc Alt cùng lúc khi nhấp vào nút hay không, trong thông số MouseEventArgs.
@page "/counter" <h1>Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount(MouseEventArgs e) { if (e.CtrlKey) // Ctrl key pressed as well { currentCount += 5; } else { currentCount++; } } }
Hiểu xử lý sự kiện trong JavaScript so với xử lý sự kiện với Blazor
Quan trọng nhất, trình xử lý sự kiện JavaScript chạy trong trình duyệt, trên máy khách. Nếu bạn đang xây dựng Ứng dụng Blazor server, trình xử lý sự kiện Blazor sẽ chạy trên máy chủ và chỉ cập nhật trình duyệt với bất kỳ thay đổi nào được thực hiện đối với giao diện người dùng khi trình xử lý sự kiện hoàn tất.Ngoài ra, cơ chế Blazor cho phép trình xử lý sự kiện truy cập dữ liệu tĩnh được chia sẻ giữa các phiên, mô hình JavaScript thì không. Tuy nhiên, việc xử lý một số sự kiện thường xuyên xảy ra chẳng hạn như @onmousemove có thể khiến giao diện người dùng trở nên chậm chạp vì chúng yêu cầu mạng vòng quanh máy chủ. Bạn có thể thích xử lý các sự kiện như những sự kiện này trong trình duyệt bằng cách sử dụng JavaScript.
Bạn có thể thao tác DOM bằng cách sử dụng mã JavaScript từ trình xử lý sự kiện cũng như sử dụng mã C# Blazor. Tuy nhiên, Blazor duy trì bản sao DOM của riêng mình, được sử dụng để làm mới giao diện người dùng khi được yêu cầu. Nếu bạn sử dụng JavaScript và mã Blazor để thay đổi các phần tử giống nhau trong DOM, bạn có nguy cơ làm hỏng DOM và có thể ảnh hưởng đến quyền riêng tư và bảo mật của dữ liệu trong ứng dụng web của bạn.
Xử lý các sự kiện không đồng bộ
Sử dụng từ khóa C# async. Phương thức phải trả về một Task
object.. Sau đó, bạn có thể sử dụng toán tử await bên trong phương thức xử lý sự kiện để bắt đầu bất kỳ tác vụ chạy dài nào trên một luồng riêng biệt và giải phóng luồng hiện tại cho công việc khác. Khi một tác vụ chạy dài hoàn thành, trình xử lý sự kiện sẽ tiếp tục. Trình xử lý sự kiện ví dụ bên dưới chạy một phương thức tốn thời gian một cách không đồng bộ:
<button @onclick="DoWork">Run time-consuming operation</button> @code { private async Task DoWork() { ... // Call a method that takes a long time to run and free the current thread var data = await timeConsumingOperation(); ... } }
xem thêm https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/
Viết inline event handlers
C # hỗ trợ các biểu thức lambda. Biểu thức lambda cho phép bạn tạo một hàm ẩn danh. Một biểu thức lambda hữu ích nếu bạn có một trình xử lý sự kiện đơn giản mà bạn không cần sử dụng lại ở những nơi khác trong trang hoặc thành phần. Trong ví dụ về số lần nhấp ban đầu được hiển thị ở phần đầu trên đơn vị này, bạn có thể loại bỏ phương thức IncrementCount và thay vào đó thay thế lời gọi phương thức bằng một biểu thức lambda thực hiện cùng một tác vụ:
@page "/counter" <h1>Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="() => currentCount++">Click me</button> @code { private int currentCount = 0; }
Cách tiếp cận này cũng hữu ích nếu bạn muốn cung cấp các đối số khác cho một phương pháp xử lý sự kiện. Trong ví dụ bên dưới, phương thức HandleClick nhận tham số MouseEventArgs giống như cách xử lý sự kiện nhấp chuột thông thường, nhưng nó cũng chấp nhận tham số chuỗi. Phương thức xử lý sự kiện nhấp chuột như trước, nhưng cũng hiển thị thông báo trong người dùng đã nhấn phím Ctrl. Biểu thức lambda gọi phương thức HandleCLick, truyền tham số MouseEventArgs (mouseEvent) và một chuỗi.
@page "/counter" @inject IJSRuntime JS <h1>Counter</h1> <p id="currentCount">Current count: @currentCount</p> <button class="btn btn-primary" @onclick='mouseEvent => HandleClick(mouseEvent, "Hello")'>Click me</button> @code { private int currentCount = 0; private async Task HandleClick(MouseEventArgs e, string msg) { if (e.CtrlKey) // Ctrl key pressed as well { await JS.InvokeVoidAsync("alert", msg); currentCount += 5; } else { currentCount++; } } }
Ví dụ này sử dụng chức năng cảnh báo JavaScript để hiển thị thông báo vì không có chức năng tương đương trong Blazor. Bạn sử dụng JavaScript interop để gọi JavaScript từ mã Blazor. Các chi tiết của kỹ thuật này là chủ đề của một mô-đun riêng biệt.
Ghi đè các DOM actions mặc định cho các sự kiện
Một số sự kiện DOM có các hành động mặc định chạy khi sự kiện xảy ra, bất kể có sẵn một trình xử lý sự kiện cho sự kiện đó hay không. Ví dụ: sự kiện @onkeypress cho phần tử <input> luôn hiển thị ký tự tương ứng với phím mà người dùng đã nhấn và xử lý thao tác nhấn phím.
Trong ví dụ tiếp theo, sự kiện @onkeypress được sử dụng để chuyển đổi đầu vào của người dùng thành chữ hoa. Ngoài ra, nếu người dùng nhập ký tự @, trình xử lý sự kiện sẽ hiển thị cảnh báo:
<input value=@data @onkeypress="ProcessKeyPress"/> @code { private string data; private async Task ProcessKeyPress(KeyboardEventArgs e) { if (e.Key == "@") { await JS.InvokeVoidAsync("alert", "You pressed @"); } else { data += e.Key.ToUpper(); } } }
Nếu bạn chạy mã này và nhấn phím @, cảnh báo sẽ được hiển thị, nhưng ký tự @ cũng sẽ được thêm vào đầu vào. Việc thêm ký tự @ là hành động mặc định của sự kiện.
Nếu bạn muốn ngăn ký tự này xuất hiện trong hộp nhập liệu, bạn có thể ghi đè hành động mặc định bằng thuộc tính PreventDefault của sự kiện, như sau:
<input value=@data @onkeypress="ProcessKeyPress" @onkeypress:preventDefault />
Sự kiện sẽ vẫn kích hoạt, nhưng chỉ các hành động được xác định bởi trình xử lý sự kiện mới được thực hiện.
Một số sự kiện trong phần tử con trong DOM có thể kích hoạt các sự kiện trong phần tử mẹ của chúng. Trong ví dụ bên dưới, phần tử <div> chứa trình xử lý sự kiện @onclick. <button> bên trong <div> có trình xử lý sự kiện @onclick của riêng nó. Ngoài ra, <div> chứa một phần tử <input>:
<div @onclick="HandleDivClick"> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> <input value=@data @onkeypress="ProcessKeyPress" @onkeypress:preventDefault /> </div> @code { private async Task HandleDivClick() { await JS.InvokeVoidAsync("alert", "Div click"); } private async Task ProcessKeyPress(KeyboardEventArgs e) { ... } private int currentCount = 0; private void IncrementCount(MouseEventArgs e) { ... } }
Khi ứng dụng chạy, nếu người dùng nhấp vào bất kỳ phần tử nào (hoặc empty space) trong khu vực bị chiếm bởi phần tử <div>, phương thức HandleDivClick sẽ chạy và hiển thị một thông báo. Nếu người dùng chọn Click me
button, phương thức IncrementCount
sẽ chạy, tiếp theo là HandleDivClick; sự kiện @onclick lan truyền cây DOM. Nếu <div> là một phần của một phần tử khác cũng xử lý sự kiện @onclick, thì trình xử lý sự kiện đó cũng sẽ chạy, v.v. tới gốc của cây DOM. Bạn có thể hạn chế sự gia tăng sự kiện này bằng thuộc tính stopPropagation của một sự kiện, như được hiển thị bên dưới:
<div @onclick="HandleDivClick"> <button class="btn btn-primary" @onclick="IncrementCount" @onclick:stopPropagation>Click me</button> ... </div>
Sử dụng EventCallback để xử lý các sự kiện trên các components
Trang Blazor có thể chứa một hoặc nhiều Blazor components và các components có thể được lồng trong mối quan hệ cha-con. Một sự kiện trong components con có thể kích hoạt phương thức xử lý sự kiện trong components mẹ bằng cách sử dụng EventCallback. Một cuộc gọi lại (callback ) tham chiếu đến một phương thức trong thành phần mẹ. component con có thể chạy phương thức bằng cách gọi lại (invoking the callback.). Cơ chế này tương tự như việc sử dụng một delegate
để tham chiếu một phương thức trong ứng dụng C #.
Một lệnh callback có thể nhận một tham số duy nhất. EventCallback là một kiểu chung. Tham số kiểu chỉ định kiểu của đối số được truyền cho callback .
Ví dụ, hãy xem xét tình huống sau. Bạn muốn tạo một component có tên TextDisplay cho phép người dùng nhập một chuỗi đầu vào và biến đổi chuỗi đó theo một cách nào đó; bạn có thể muốn chuyển nó thành chữ hoa, chữ thường, chữ hoa hỗn hợp, lọc các ký tự từ nó hoặc thực hiện một số kiểu chuyển đổi khác. Tuy nhiên, khi bạn viết mã cho component TextDisplay, bạn không biết quá trình chuyển đổi sẽ như thế nào, và thay vào đó muốn trì hoãn hoạt động này cho component khác.
component TextTransformer là một trang Blazor tạo ra một thể hiện của component TextDisplay. Nó điền tham số OnKeypressCallback với tham chiếu đến phương thức TransformText trong phần mã của trang. Phương thức TransformText lấy đối tượng KeyTransformation được cung cấp làm đối số của nó và điền vào thuộc tính TransformedKey với giá trị được tìm thấy trong thuộc tính Khóa được chuyển đổi thành chữ hoa. Sơ đồ bên dưới minh họa luồng điều khiển khi người dùng nhập giá trị vào trường <input> trong thành phần TextDisplay được hiển thị bởi trang TextTransformer: