Sử dụng JavaScript trong Blazor apps

Blazor cho phép bạn tích hợp các thư viện JavaScript vào ứng dụng của mình bằng cách sử dụng khả năng tương tác Blazor JavaScript hoặc tương tác JS.

Hiểu khả năng tương tác của JavaScript với Blazor

Blazor cho phép bạn tích hợp các thư viện JavaScript vào ứng dụng của mình bằng cách sử dụng khả năng tương tác Blazor JavaScript hoặc tương tác JS. Bạn sử dụng JS interop để gọi các hàm JavaScript từ các phương thức .NET và gọi các phương thức .NET từ các hàm JavaScript. JS interop xử lý việc sắp xếp dữ liệu và các tham chiếu đối tượng giữa Blazor và JavaScript để làm cho việc chuyển đổi giữa chúng dễ dàng nhất có thể.

Blazor duy trì biểu diễn Document Object Model (DOM) của riêng mình dưới dạng một cây kết xuất ảo (virtual render tree). Khi cấu trúc trang thay đổi, Blazor tạo một cây kết xuất mới chứa các điểm khác biệt. Khi các thay đổi hoàn tất, Blazor lặp lại các điểm khác biệt này để cập nhật giao diện người dùng được Trình duyệt hiển thị và phiên bản Trình duyệt của DOM được JavaScript sử dụng. Nếu mã JavaScript của bạn sửa đổi các phần tử của DOM, biểu diễn Blazor có thể không còn khớp với trạng thái hiện tại. Điều này có thể dẫn đến hành vi không mong muốn và có thể gây ra rủi ro bảo mật. Phần Cập nhật DOM bằng JavaScript sử dụng đối tượng ElementReference ở phần sau trong đơn vị này tóm tắt cách bạn có thể giải quyết vấn đề này.

Load JavaScript code trong một Blazor app

Sử dụng phần tử <script> để tải mã JavaScript, giống như cách bạn sử dụng phần tử này trong một ứng dụng web HTML thông thường.

<!DOCTYPE html>
<html lang="en">
<head>
...
</head>
<body>
...

<script src="_framework/blazor.server.js"></script>
<script src="js/gauge.min.js"></script>
<script>
window.myFunc = (param1, param2) => {
...
</script>
</body>

Đặt các file JavaScript trong thư mục wwwroot của ứng dụng Blazor. Trong ví dụ trên, tệp gauge.js được thu nhỏ nằm trong thư mục wwwroot / js của ứng dụng.

Gọi JavaScript từ .NET code

Bạn sử dụng JS interop runtime để gọi một hàm JavaScript từ mã .NET. Để JS interop runtime được hoạt động, hãy inject một phiên bản của phần trừu tượng IJSRuntime vào trang Blazor, sau chỉ thị @page ở đầu tệp. Ví dụ bên dưới sử dụng trang tìm nạp dữ liệu từ ứng dụng Blazor Server mặc định. Ví dụ này thêm một thuộc tính có tên JS vào trang mà bạn có thể sử dụng để chạy các hàm tương tác JS:

@page "/fetchdata"

@using MyWebApplication.Data
@inject WeatherForecastService ForecastService
@inject IJSRuntime JS

<h1>Weather forecast</h1>
...

JS interop cung cấp hai phương thức mà bạn sử dụng để gọi mã JavaScript: InvokeAsyncInvokeVoidAsync. Sử dụng InvokeAsync để gọi một hàm JavaScript trả về một giá trị, nếu không hãy chạy InvokeVoidAsync.

Như tên gợi ý, cả hai phương thức đều bất đồng bộ, vì vậy hãy sử dụng toán tử C # await để thu thập bất kỳ kết quả nào. Các tham số của phương thức InvokeAsync và InvokeVoidAsync là tên của hàm JavaScript cần gọi, theo sau là bất kỳ đối số nào được hàm yêu cầu. Hàm JavaScript phải là một phần của phạm vi cửa sổ hoặc một phạm vi phụ của cửa sổ. Các đối số phải có thể tuần tự hóa dưới dạng JSON.

JS interop chỉ khả dụng khi ứng dụng Blazor Server đã thiết lập kết nối SignalR với trình duyệt. Bạn không thể thực hiện các interop calls cho đến khi rendering  hoàn tất. Để phát hiện xem rendering  đã hoàn tất hay chưa, hãy sử dụng sự kiện OnAfterRender trong mã Blazor của bạn. Đơn vị Cải thiện khả năng tương tác của ứng dụng với các sự kiện vòng đời sau trong mô-đun này mô tả sự kiện này chi tiết hơn.

Ví dụ: Cập nhật title trong page header.

Code trong body của Blazor Server component không có quyền truy cập trực tiếp vào phần tử <head> của trang mà nó được hiển thị trên đó. Nếu bạn cần sửa đổi một số khía cạnh của tiêu đề, bạn có thể sử dụng JS interop để gọi một hàm JavaScript thực hiện điều này cho bạn.

Ví dụ: nếu bạn muốn thay đổi tiêu đề của trang được trình duyệt hiển thị để phản ánh mục đích của thành phần được hiển thị, bạn có thể gọi một hàm JavaScript cập nhật thẻ <title> trong phần tử <head>. Hàm changeTitle của JavaScript bên dưới hiển thị một ví dụ:

<script>
  window.changeTitle = async (newTitle) => {
  document.title = newTitle;
  };
</script>

Để chạy hàm changeTitle từ một Blazor component, hãy gọi phương thức InvokeVoidAsync trong trình xử lý sự kiện OnAfterRenderAsync và cung cấp tiêu đề mới dưới dạng tham số. Ví dụ bên dưới dành cho thành phần FetchData.razor hiển thị thông tin dự báo thời tiết:

@code {
...

 protected override async Task OnAfterRenderAsync(bool firstRender)
 {
   if (firstRender)
  {
    await JS.InvokeVoidAsync("changeTitle", "Weather Forecast");
   }
 }
...
}

Tiêu đề mới xuất hiện trong tab trình duyệt khi người dùng chọn trang Tìm nạp dữ liệu:

blazor-fetch-data-page-new-title

Cập nhật DOM bằng JavaScript bằng đối tượng ElementReference

Nhiều thư viện JavaScript của bên thứ ba có sẵn để hiển thị các phần tử trên một trang. Các thư viện này thực hiện cập nhật DOM. Như đã mô tả trước đó, Blazor duy trì bản sao DOM của riêng mình và điều quan trọng là không thực hiện các thay đổi có thể khiến chế độ xem Blazor của DOM bị hỏng.

cách đơn giản nhất để xử lý tình huống này là tạo placeholder element trong  Blazor component. Thông thường, bạn có thể sử dụng phần tử <div>. Mã Blazor của bạn chỉ xem nội dung này là một khoảng trống và cây kết xuất Blazor không cố gắng theo dõi nội dung của nó. Trong mã JavaScript của mình, bạn có thể tự do thêm các phần tử vào <div> này và Blazor sẽ không cố gắng thay đổi nó. Thông thường, bạn có thể sử dụng phần tử <div>. Mã Blazor của bạn chỉ xem nội dung này là một khoảng trống và cây kết xuất Blazor không cố gắng theo dõi nội dung của nó. Trong mã JavaScript của mình, bạn có thể tự do thêm các phần tử vào <div> này và Blazor sẽ không cố gắng thay đổi nó.

Bạn chuyển một tham chiếu đến một phần tử từ Blazor sang JavaScript bằng cách tạo một đối tượng ElementReference. Đoạn bên dưới hiển thị một phần tử <div> được thêm vào trang dữ liệu Tìm nạp được sử dụng trong các ví dụ trước. <div> này sẽ được sử dụng để hiển thị biểu đồ đường thể hiện nhiệt độ dao động như thế nào trong khoảng thời gian được dự báo thời tiết đề cập. Mã JavaScript sẽ sử dụng thư viện đồ họa mã nguồn mở có tên là Plotly để tạo biểu đồ. Để biết thêm thông tin về Plotly, hãy truy cập Thư viện đồ thị mã nguồn mở Plotly JavaScript. Bạn tạo một tham chiếu phần tử với thuộc tính @ref và khai báo trường ElementReference trong mã Blazor của bạn có cùng tên. Sau đó, bạn có thể chuyển tham chiếu phần tử này đến một hàm JavaScript bằng cách sử dụng JS interop, như được hiển thị ở đây. Trong ví dụ này, hàm JavaScript được đặt tên là showGraph. Tham chiếu đến phần tử <div> và một mảng chứa nhiệt độ dự báo theo độ C, được cung cấp dưới dạng các đối số:

 

@page "/fetchdata"
...
@inject IJSRuntime JS

<h1>Weather forecast</h1>

...
<table class="table">
...
</table>

<div @ref=graphPlaceholder></div>
}

@code {
...
private ElementReference graphPlaceholder;

protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
...
var forecastTemperatures = (from t in forecasts
select t.TemperatureC).ToArray();

await JS.InvokeVoidAsync("showGraph", graphPlaceholder, forecastTemperatures);
}
}

...
}

Trong ví dụ này, tệp @ Page / _Host.cshtml bao gồm các phần tử tập lệnh sau. Tập lệnh đầu tiên tải thư viện Plotly. Tập lệnh thứ hai tạo hàm showGraph. Hàm showGraph sử dụng thư viện Plotly để vẽ biểu đồ đường trong phần tử <div> được chỉ định:

<body>
...
<script src="https://cdn.plot.ly/plotly-2.3.1.min.js"></script>
<script>
  window.showGraph = (graphDiv, data) => {
   var plotData = {y: data, type: 'lines'};
   Plotly.newPlot(graphDiv, [plotData], {title: 'Celsius Temperatures by Day'});
}
</script>
</body>

Khi ứng dụng chạy và hiển thị trang Dữ liệu tìm nạp, biểu đồ xuất hiện bên dưới bảng:

blazor-fetch-data-page-graph

Làm cho JS tương tác mạnh mẽ

Hãy nhớ rằng Blazor server  đang chạy ứng dụng Blazor của bạn và trình duyệt chạy mã JavaScript mà bạn gọi từ Blazor, đang chạy trên các quy trình khác nhau. Các quy trình này giao tiếp bằng SignalR qua kết nối mạng. Các mạng dễ bị mất kết nối có thể dẫn đến các ngoại lệ trong mã của bạn. Nếu một ngoại lệ xảy ra khi gọi các phương thức InvokeAsync hoặc InvokeVoidAsync, do sự cố mạng hoặc do một số lỗi ứng dụng, JS interop sẽ ném ra một ngoại lệ JSException. Bạn nên chuẩn bị để nắm bắt và xử lý ngoại lệ này trong mã Blazor của mình.

Theo mặc định, JS interop sẽ đợi tối đa một phút để network call thành công trước khi hết thời gian với một ngoại lệ. Bạn có thể thay đổi thời gian chờ này trên toàn cầu trên toàn bộ ứng dụng Blazor Server của mình hoặc trên cơ sở từng cuộc gọi. Để đặt thời gian chờ chung, hãy định cấu hình các tùy chọn mạch trong phần “Thêm Dịch vụ vào vùng chứa” của tệp Program.cs. Ví dụ: để tăng khoảng thời gian chờ lên 120 giây, hãy sử dụng mã hiển thị bên dưới:

// Add services to the container.
...
builder.Services.AddServerSideBlazor(options => options.JSInteropDefaultCallTimeout = TimeSpan.FromSeconds(120));
...

Để chỉ định thời gian chờ cho một call cụ thể, hãy cung cấp khoảng thời gian chờ làm tham số thứ hai cho các phương thức InvokeAsync hoặc InvokeVoidAsync (các phương thức này được nạp chồng). Ví dụ:

await JS.InvokeVoidAsync("showGraph", TimeSpan.FromSeconds(30), graphPlaceholder, forecastTemperatures);

Khoảng thời gian chờ được chỉ định cho một lệnh gọi hàm sẽ ghi đè bất kỳ khoảng thời gian chờ chung nào được định cấu hình trước đó.

Bài tiếp theo: Gọi mã .NET từ JavaScript

theo: https://docs.microsoft.com/en-us/learn/modules/blazor-build-rich-interactive-components/2-create-user-interfaces-blazor-components

One thought on “Sử dụng JavaScript trong Blazor apps

  1. Pingback: Call .NET code từ JavaScript trong Blazor apps | Phạm Duy Anh

Leave a Reply

Your email address will not be published.