Không phải lúc nào nhà phát triển cũng dễ dàng tích hợp các tính năng chỉnh sửa nâng cao vào ứng dụng web của họ. 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 tuý và tài liệu HTML bằng các phần tử như <input>
và <textarea>
hoặc bằng cách áp dụng thuộc tính contenteditable
cho các phần tử. Tuy nhiên, các chức năng cơ bản của các loại phần tử này thường không đủ cho những gì nhà phát triển muốn đạt được trong ứng dụng của họ.
Nhà phát triển thường triển khai thành công chế độ xem 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. Chế độ xem trình chỉnh sửa có thể được tạo bằng một DOM phức tạp hoặc thậm chí bằng một phần tử <canvas>
. Tuy nhiên, vì cách duy nhất để nhà phát triển nhận được dữ liệu nhập văn bản là cần có một phần tử có thể chỉnh sửa được lấy làm tâm điểm, nên họ vẫn cần đặt một phần tử contenteditable
ẩn ở đâu đó trên trang.
Kết quả là mặc dù người dùng có vẻ như đang trực tiếp chỉnh sửa nội dung trong chế độ xem trình chỉnh sửa tuỳ chỉnh của ứng dụng, nhưng nhà phát triển thực sự đang nhận dữ liệu đầu vào bằng trình xử lý sự kiện trong phần tử ẩn, sau đó phản ánh dữ liệu đó vào chế độ xem trình chỉnh sửa hiển thị. Điều này có thể dẫn đến sự cố khi nhà phát triển phải đối phó với hành vi chỉnh sửa mặc định của trình duyệt trong phần tử contenteditable
bị ẩn.
Để giải quyết loại vấn đề này, nhóm Microsoft Edge đã thúc đẩy việc chuẩn hoá EditContext, một API nền tảng web mới cho phép nhà phát triển nhận trực tiếp dữ liệu nhập văn bản mà không bị ràng buộc với các hành vi chỉnh sửa mặc định của trình duyệ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 người khác. 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, thì 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 cấu trúc. Điều này là do việc thay đổi phần 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 thành phần này bị huỷ sớm. Ứng dụng phải đợi cho đến khi cửa sổ IME đóng để cập nhật chế độ xem, điều này có thể gây ra độ trễ và cản trở việc cộng tác.
Để 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 một cách để tách dữ liệu nhập văn bản từ chế độ xem HTML DOM. API EditContext là giải pháp cho vấn đề này.
Kiến thức cơ bản về EditContext
Với EditContext, bạn có thể nhận dữ liệu đầu vào văn bản và thành phần trực tiếp thông qua giao diện API EditContext, thay vì thông qua việc quan sát các thay đổi đối với DOM. Điều này cho phép kiểm soát chặt chẽ hơn cách xử lý dữ liệu đầu vào, thậm chí cho phép thêm khả năng chỉnh sửa vào phần tử <canvas>
.
Việc liên kết một thực thể EditContext với một phần tử sẽ giúp phần tử đó có thể chỉnh sửa:
// 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ổ thành phần IME, bộ chọn biểu tượng cảm xúc và các nền tảng nhập dữ liệu 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à lựa chọn, bạn còn phải làm một số việc khác khi sử dụng API EditContext.
Quản lý cạnh của một vùng có thể chỉnh sửa hoặc nếu lựa chọn của người dùng thay đổi
Gọi các phương thức updateControlBounds()
và updateSelectionBounds()
để thông báo cho thực thể EditContext bất cứ khi nào kích thước của vùng 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 khác dành riêng cho nền tảng.
// 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í của giao diện người dùng của trình chỉnh sửa
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 khác dành riêng cho nền tảng.
Đang áp dụng định dạng
Theo dõi sự kiện textformatupdate
và áp dụng định dạng do sự kiện chỉ định cho chế độ xem trình chỉnh sửa. Các phần 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ụ: IME tiếng Nhật sẽ sử dụng đường gạch dưới để cho biết phần văn bản nào đang được soạn.
Xử lý hành vi 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ư phím tắt để in đậm hoặc in nghiêng văn bản hoặc áp dụng tính năng kiểm tra 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 nhập bằng bàn phím hoặc chuột, bạn cần thông báo cho thực thể EditContext về thay đổi đó. Điều này là cần thiết vì EditContext API có thể áp dụng cho nhiều trường hợp sử dụng, bao gồm cả các trình chỉnh sửa được hiển thị bằng phần tử <canvas>
mà trình duyệt không thể tự động phát hiện các thay đổi về 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 các hành vi chọn và điều hướng con nháy, chẳng hạn như di chuyển 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 chính tả tích hợp 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 đầy đủ tính năng và muốn có toàn quyền kiểm soát cách xử lý hoạt động nhập văn bản, hoặc nếu bạn đang thêm các tính năng nâng cao như đồ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 nêu trên để sử dụng EditContext, nếu tất cả những gì bạn cần là sự hỗ trợ chỉnh sửa văn bản đơn giản, bạn có thể 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 tính năng EditContext trong Chromium thông qua sự cộng tác với các kỹ sư của Chrome. Dự án này sẽ được triển khai cùng bản phát hành 121 (tháng 1 năm 2024) của cả Chrome và Edge. Hiện tại, API này chỉ có trong các trình duyệt dựa trên Chromium, nhưng bạn có thể đọc quan điểm của Mozilla và WebKit về API EditContext.
Chúng tôi muốn giúp các nhà phát triển web dễ dàng tạo ra trải nghiệm chỉnh sửa tuỳ chỉnh mạnh mẽ trên web. Chúng tôi tin rằng EditContext API sẽ giúp đạt được điều này bằng cách giải quyết các thách thức hiện tại và cung cấp cách trực tiếp hơn để xử lý dữ liệu 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, 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, hãy gửi lỗi tại crbug.com.