Giới thiệu cách mới để tạo trải nghiệm chỉnh sửa web tuỳ chỉnh bằng API EditContext

Việc kết hợp các tính năng chỉnh sửa nâng cao vào các ứng dụng web của họ không phải là việc đơn giản đối với các nhà phát triển. Nền tảng web cung cấp khả năng chỉnh sửa cho cả tài liệu văn bản thuần túy và tài liệu HTML bằng cách sử dụng các phần tử như <input><textarea> hoặc bằng cách áp dụng thuộc tính contenteditable cho các phần tử. Tuy nhiên, chức năng cơ bản của các loại phần tử này thường là không đủ cho những gì nhà phát triển muốn đạt được trong ứng dụng của họ.

Các nhà phát triển thường kết thúc việc triển khai khung hiển thị trình chỉnh sửa tuỳ chỉnh của riêng họ để triển khai chức năng mà người dùng cần. Bạn có thể xây dựng khung hiển thị trình chỉnh sửa bằng một DOM phức tạp hoặc thậm chí bằng phần tử <canvas>. Tuy nhiên, vì cách duy nhất để nhà phát triển nhận dữ liệu nhập văn bản là yêu cầu một phần tử có thể chỉnh sửa tập trung, nên họ vẫn cần đặt một phần tử contenteditable ẩn trên trang của mình ở đâu đó.

Kết quả là người dùng dường như đang trực tiếp chỉnh sửa nội dung trong khung hiển thị trình chỉnh sửa tuỳ chỉnh của ứng dụng, nhưng thực ra nhà phát triển sẽ nhận dữ liệu đầu vào qua trình xử lý sự kiện trong phần tử bị ẩn, sau đó phản chiếu nội dung đó vào khung hiển thị trình chỉnh sửa có thể nhìn thấy. Điều này có thể gây ra vấn đề vì nhà phát triển gặp phải hành vi chỉnh sửa mặc định của trình duyệt trong phần tử contenteditable ẩn.

Để giải quyết loại vấn đề này, nhóm Microsoft Edge đã tiến hành tiêu chuẩn hoá EditContext, một API nền tảng web mới cho phép nhà phát triển nhập trực tiếp văn bản mà không bị ràng buộc với hành vi chỉnh sửa mặc định của trình duyệt.

Một ví dụ thực tế

Ví dụ: khi người dùng đang cộng tác trong Word Online. Người dùng có thể cùng chỉnh sửa và xem các thay đổi cũng như vị trí con trỏ của nhau. Tuy nhiên, nếu một cộng tác viên đang sử dụng cửa sổ Trình chỉnh sửa phương thức nhập (IME) để soạn văn bản tiếng Nhật, trình chỉnh sửa của họ sẽ không được cập nhật để hiển thị các thay đổi từ người dùng khác cho đến khi người dùng IME hoàn tất việc soạn. Điều này là do việc thực hiện các thay đổi đối với khu vực DOM đang được chỉnh sửa trong khi có một thành phần IME đang hoạt động có thể khiến cấu trúc bị huỷ sớm. Ứng dụng phải đợi cho đến khi đóng cửa sổ IME để cập nhật chế độ xem. Điều này có thể gây ra sự chậm trễ và cản trở hoạt động cộng tác.

Sự cố khi cộng tác trong Word Online khi soạn văn bản

Để cung cấp trải nghiệm tốt hơn cho cả nhà phát triển và người dùng, nhà phát triển cần có cách để tách văn bản nhập từ chế độ xem HTML DOM. API EditContext là giải pháp cho vấn đề này.

Thông tin cơ bản về EditContext

Với EditContext, bạn có thể nhận văn bản và thành phần đầu vào trực tiếp thông qua nền tảng API EditContext, thay vì thông qua việc quan sát các thay đổi đối với DOM. Điều này giúp kiểm soát chặt chẽ hơn cách xử lý dữ liệu đầu vào và thậm chí còn cho phép thêm khả năng chỉnh sửa cho phần tử <canvas>.

Liên kết một thực thể EditContext với một phần tử có thể chỉnh sửa được:

// This will be our editable element.
const element = document.querySelector('#editor-element');

// Creating the EditContext object.
const editContext = new EditContext();

// Associating the EditContext object with our DOM element.
// The element is now focusable and can receive text input.
element.editContext = editContext;

// In order to render the text typed by the user onto the
// page, as well as the user's selection, you'll need to
// receive the input in a textupdate event callback.
editContext.addEventListener('textupdate', event => {
  element.textContent = editContext.text;

  // For brevity, the code to render the selection
  // isn't shown here.
    renderSelection(event.selectionStart, event.selectionEnd);
 });

Trách nhiệm của tác giả

Việc sử dụng API EditContext giúp bạn dễ dàng hỗ trợ các phương thức nhập nâng cao, chẳng hạn như cửa sổ kết hợp IME, bộ chọn biểu tượng cảm xúc và các nền tảng nhập khác của hệ điều hành. Để thực hiện tất cả những việc này trong phần tử có thể chỉnh sửa, API EditContext cần một số thông tin. Ngoài việc hiển thị văn bản và vùng lựa chọn, bạn cũng phải làm một số việc khác khi sử dụng API EditContext.

Quản lý bên cạnh một khu vực có thể chỉnh sửa hoặc nếu lựa chọn của người dùng thay đổi

Gọi phương thức updateControlBounds()updateSelectionBounds() để thông báo cho thực thể EditContext mỗi khi kích thước của khu vực có thể chỉnh sửa hoặc lựa chọn của người dùng thay đổi. Điều này giúp nền tảng quyết định vị trí hiển thị cửa sổ IME và giao diện người dùng chỉnh sửa dành riêng cho nền tảng khác.

// It's necessary to provide bounds information because EditContext
// is generic enough to work with any type of web editor, even
// <canvas>-based editors. The API doesn't make any assumptions as
// to how the editor is implemented or how the selection is rendered.
// Bounds are given in the client coordinate space.
const controlBound = editorElement.getBoundingClientRect();
const selection = document.getSelection();
const selectionBound = selection.getRangeAt(0).getBoundingClientRect();
editContext.updateControlBounds(controlBound);
editContext.updateSelectionBounds(selectionBound);

Quản lý vị trí trong giao diện người dùng của trình chỉnh sửa

Hãy theo dõi sự kiện characterboundsupdate và gọi updateCharacterBounds() để phản hồi nhằm giúp nền tảng quyết định vị trí hiển thị cửa sổ IME và giao diện người dùng chỉnh sửa dành riêng cho nền tảng khác.

Đang áp dụng định dạng

Theo dõi sự kiện textformatupdate và áp dụng định dạng mà sự kiện chỉ định cho chế độ xem trình chỉnh sửa. Các trang trí văn bản này được IME sử dụng khi soạn một số ngôn ngữ nhất định. Ví dụ: một IME tiếng Nhật sẽ sử dụng dấu gạch dưới để cho biết phần văn bản nào đang được soạn.

Ảnh chụp màn hình cửa sổ Trình chỉnh sửa phương thức nhập được dùng để nhập các ký tự tiếng Nhật.

Xử lý hoạt động chỉnh sửa văn bản đa dạng thức

Theo dõi sự kiện beforeinput để xử lý mọi hành vi chỉnh sửa văn bản đa dạng thức mà bạn muốn hỗ trợ, chẳng hạn như các phím tắt để in đậm hoặc in nghiêng văn bản hoặc áp dụng tính năng sửa lỗi chính tả.

Quản lý các thay đổi trong lựa chọn của người dùng

Khi lựa chọn của người dùng thay đổi do thao tác đầu vào bằng bàn phím hoặc chuột, bạn cần thông báo cho thực thể EditContext về sự thay đổi này. Điều này là cần thiết vì API EditContext có thể áp dụng cho nhiều trường hợp sử dụng, bao gồm cả trình chỉnh sửa được kết xuất bằng phần tử <canvas> nơi trình duyệt không thể tự động phát hiện các thay đổi đối với lựa chọn.

document.addEventListener('selectionchange', () => {
  const selection = document.getSelection();

  // EditContext doesn't handle caret navigation, so all the caret navigation/selection that happens
  // in DOM space needs to be mapped to plain text space by the author and passed to EditContext.
  // This example code assumes the editable area only contains text under a single node.
  editContext.updateSelection(selection.anchorOffset, selection.focusOffset);
});

Nếu phần tử bạn đang sử dụng với EditContext là phần tử <canvas>, bạn cũng cần triển khai hành vi điều hướng lựa chọn và con nháy, chẳng hạn như điều hướng qua văn bản bằng các phím mũi tên. Ngoài ra, tính năng kiểm tra lỗi chính tả tích hợp sẵn của trình duyệt chỉ hoạt động trong các phần tử không phải <canvas>.

EditContext so với contenteditable

EditContext là một lựa chọn tuyệt vời nếu bạn đang triển khai một trình chỉnh sửa có đầy đủ tính năng và muốn có toàn quyền kiểm soát cách xử lý văn bản nhập, hoặc nếu bạn đang thêm các tính năng nâng cao như cùng chỉnh sửa với nhiều người dùng. Tuy nhiên, dựa trên tất cả yêu cầu trước đó để sử dụng EditContext, nếu tất cả những gì bạn cần là hỗ trợ chỉnh sửa văn bản đơn giản, thì có thể bạn vẫn cần sử dụng các phần tử <input>, <textarea> hoặc thuộc tính contenteditable.

Hướng đến tương lai

Nhóm Microsoft Edge đã triển khai EditContext trong Chromium thông qua sự cộng tác với các kỹ sư Chrome và đang vận chuyển cùng với bản phát hành 121 (tháng 1 năm 2024) cho cả Chrome và Edge. Hiện tại, tính năng này chỉ có trong trình duyệt dựa trên Chromium nhưng bạn có thể đọc vị trí của MozillaWebKit trên API EditContext.

Chúng tôi muốn các nhà phát triển web dễ dàng xây dựng trải nghiệm chỉnh sửa tuỳ chỉnh mạnh mẽ trên web. Chúng tôi tin rằng API EditContext làm được điều này nhờ giải quyết được những thách thức hiện có và cung cấp một cách trực tiếp hơn để xử lý việc nhập văn bản.

Nếu bạn muốn tìm hiểu thêm về API này, hãy tham khảo tài liệu về MDN. Để gửi ý kiến phản hồi về thiết kế của API này, hãy mở một vấn đề trong kho lưu trữ GitHub của API EditContext. Để báo cáo lỗi khi triển khai API này, hãy gửi lỗi tại crbug.com.