Khi sao chép văn bản từ một trang web vào bảng tạm của thiết bị, rất có thể bạn sẽ nhận được HTML đã định dạng khi dán. Một số ứng dụng và hệ điều hành có tính năng "Dán đặc biệt" sẽ xóa các thẻ đó để bạn duy trì kiểu hiện tại, nhưng bạn sẽ làm gì nếu tính năng đó không khả dụng?
Tương tự như khi chuyển đổi văn bản thuần túy thành HTML có định dạng. Một trong những cách gần nhất mà chúng ta có thể chuyển đổi văn bản thuần túy thành HTML là viết trong Markdown dưới dạng trừu tượng. Bạn có thể đã thấy các ví dụ về điều này trong nhiều biểu mẫu bình luận trong các bài viết giống như bài viết này. Viết bình luận trong Markdown và nó sẽ được phân tích cú pháp dưới dạng HTML.
Thậm chí còn tốt hơn nếu không có bất kỳ sự trừu tượng nào! Bạn cũng có thể đã thấy (và sử dụng) một số công cụ trực tuyến lấy văn bản được viết thuần túy và chuyển đổi thành HTML có định dạng. Giao diện người dùng thực hiện chuyển đổi và xem trước kết quả đã định dạng theo thời gian thực.
Cung cấp cho người dùng một cách để tạo nội dung web cơ bản — như bình luận — mà không cần biết bất kỳ điều gì về HTML, là một mục tiêu mới lạ vì nó làm giảm rào cản trong việc giao tiếp và cộng tác trên web. Nói rằng nó giúp "dân chủ hóa" web có thể là hơi quá, nhưng nó không xung đột với tầm nhìn đó!

Chúng ta có thể tự mình xây dựng một công cụ như thế này. Tôi hoàn toàn ủng hộ việc sử dụng các tài nguyên hiện có khi có thể, nhưng tôi cũng muốn chứng minh cách thức hoạt động của những thứ này và có thể học được điều gì đó mới trong quá trình này.
Một lần nữa, ý tưởng là người dùng phải có thể viết mà không cần biết cú pháp Markdown hoặc HTML. Đây là một hạn chế lớn và có quá nhiều phần tử HTML mà chúng ta có thể gặp phải, vì vậy, điều đáng để biết bối cảnh mà nội dung đang được sử dụng. Ví dụ, nếu đây là công cụ để viết bài đăng trên blog, thì chúng ta có thể giới hạn phạm vi các thành phần được hỗ trợ dựa trên các thành phần thường được sử dụng trong nội dung dạng dài:
Việc triển khai giao diện người dùng sẽ dựa trên HTML, CSS và JavaScript thuần túy để thiết lập một biểu mẫu nhỏ với bố cục và chức năng đơn giản giúp chuyển đổi văn bản thành HTML. Có một khía cạnh về phía máy chủ đối với điều này nếu bạn có kế hoạch triển khai nó vào môi trường sản xuất, nhưng trọng tâm của chúng tôi chỉ tập trung vào giao diện người dùng.
[*]
Nhưng TinyMCE không phải là gói hiệu quả nhất với dung lượng khoảng 500 KB sau khi thu nhỏ. Đó không phải là lời chỉ trích mà là dấu hiệu cho thấy nó bao phủ bao nhiêu chức năng. Chúng tôi muốn thứ gì đó "cơ bản" hơn thế cho mục đích đơn giản của mình. Tìm kiếm trên GitHub sẽ cho ra nhiều khả năng hơn. Tuy nhiên, các giải pháp có vẻ như thuộc một trong hai loại sau:
Xem Bút [Kiểu Biểu mẫu Cơ sở [phân nhánh]](https://codepen.io/smashingmag/pen/OJGoNOX) của Geoff Graham.
Xem Bút Kiểu Biểu mẫu Cơ sở [phân nhánh] của Geoff Graham.
Bạn có thể phát triển thêm CSS, nhưng đó không phải là trọng tâm của bài viết này. Không còn nghi ngờ gì nữa, thiết kế có thể đẹp hơn những gì tôi cung cấp ở đây!
Trong JavaScript, hàm
Mã hóa HTML của đầu vào là một cân nhắc bảo mật quan trọng. Nó ngăn chặn các tập lệnh không mong muốn hoặc các thao tác HTML khác xâm nhập vào công việc của chúng ta. Thật vậy, việc khử trùng và xác thực đầu vào ở phía trước chỉ là biện pháp ngăn chặn vì những kẻ xấu có thể bỏ qua chúng. Nhưng chúng ta cũng có thể khiến chúng hoạt động mạnh hơn một chút.
Miễn là chúng ta đang nói về chủ đề bảo mật công việc của mình, hãy đảm bảo mã hóa HTML cho đầu vào ở phía sau, nơi người dùng không thể can thiệp. Đồng thời, hãy cẩn thận không mã hóa đầu vào nhiều hơn một lần. Mã hóa văn bản đã được mã hóa HTML sẽ phá vỡ chức năng đầu ra. Cách tiếp cận tốt nhất cho lưu trữ back-end là front-end chuyển đầu vào thô, chưa mã hóa đến back-end, sau đó yêu cầu back-end mã hóa HTML đầu vào trước khi chèn vào cơ sở dữ liệu.
Điều đó nói rằng, điều này chỉ tính đến việc vệ sinh và lưu trữ đầu vào ở back-end. Chúng ta vẫn phải hiển thị đầu ra HTML được mã hóa ở front-end. Có ít nhất hai cách tiếp cận cần xem xét:
Tóm lại, đoạn mã nhỏ này lặp qua mảng các dòng văn bản bị chia tách và bỏ qua các dòng không chứa bất kỳ ký tự văn bản nào. Từ đó, chúng ta có thể đánh giá xem một dòng có phải là dòng đầu tiên trong chuỗi hay không. Nếu có, chúng ta sẽ gắn thẻ
Logic này có thể được sử dụng để tính đến các loại phần tử khác mà bạn có thể muốn đưa vào đầu ra. Ví dụ, có lẽ dòng thứ hai được coi là dòng ghi chú nêu tên tác giả và liên kết đến kho lưu trữ tất cả các bài đăng của tác giả.
Tương tự như khi chuyển đổi văn bản thuần túy thành HTML có định dạng. Một trong những cách gần nhất mà chúng ta có thể chuyển đổi văn bản thuần túy thành HTML là viết trong Markdown dưới dạng trừu tượng. Bạn có thể đã thấy các ví dụ về điều này trong nhiều biểu mẫu bình luận trong các bài viết giống như bài viết này. Viết bình luận trong Markdown và nó sẽ được phân tích cú pháp dưới dạng HTML.
Thậm chí còn tốt hơn nếu không có bất kỳ sự trừu tượng nào! Bạn cũng có thể đã thấy (và sử dụng) một số công cụ trực tuyến lấy văn bản được viết thuần túy và chuyển đổi thành HTML có định dạng. Giao diện người dùng thực hiện chuyển đổi và xem trước kết quả đã định dạng theo thời gian thực.
Cung cấp cho người dùng một cách để tạo nội dung web cơ bản — như bình luận — mà không cần biết bất kỳ điều gì về HTML, là một mục tiêu mới lạ vì nó làm giảm rào cản trong việc giao tiếp và cộng tác trên web. Nói rằng nó giúp "dân chủ hóa" web có thể là hơi quá, nhưng nó không xung đột với tầm nhìn đó!

Chúng ta có thể tự mình xây dựng một công cụ như thế này. Tôi hoàn toàn ủng hộ việc sử dụng các tài nguyên hiện có khi có thể, nhưng tôi cũng muốn chứng minh cách thức hoạt động của những thứ này và có thể học được điều gì đó mới trong quá trình này.
Xác định phạm vi
Có rất nhiều giả định và cân nhắc có thể đưa vào bộ chuyển đổi văn bản thuần túy sang HTML. Ví dụ, chúng ta có nên cho rằng dòng văn bản đầu tiên được nhập vào công cụ là tiêu đề cần các thẻ[HEADING=1]
tương ứng không? Mỗi dòng mới có thực sự là một đoạn văn không và liên kết nội dung phù hợp với điều này như thế nào?Một lần nữa, ý tưởng là người dùng phải có thể viết mà không cần biết cú pháp Markdown hoặc HTML. Đây là một hạn chế lớn và có quá nhiều phần tử HTML mà chúng ta có thể gặp phải, vì vậy, điều đáng để biết bối cảnh mà nội dung đang được sử dụng. Ví dụ, nếu đây là công cụ để viết bài đăng trên blog, thì chúng ta có thể giới hạn phạm vi các thành phần được hỗ trợ dựa trên các thành phần thường được sử dụng trong nội dung dạng dài:
,
,
và
. Nói cách khác, có thể bao gồm các tiêu đề cấp cao nhất, văn bản thân bài, văn bản được liên kết và hình ảnh. Sẽ không có hỗ trợ cho danh sách có dấu đầu dòng hoặc có thứ tự, bảng hoặc bất kỳ thành phần nào khác cho công cụ cụ thể này.Việc triển khai giao diện người dùng sẽ dựa trên HTML, CSS và JavaScript thuần túy để thiết lập một biểu mẫu nhỏ với bố cục và chức năng đơn giản giúp chuyển đổi văn bản thành HTML. Có một khía cạnh về phía máy chủ đối với điều này nếu bạn có kế hoạch triển khai nó vào môi trường sản xuất, nhưng trọng tâm của chúng tôi chỉ tập trung vào giao diện người dùng.
[*]
Xem các giải pháp hiện có
Có những cách hiện có để thực hiện điều này. Ví dụ, một số thư viện cung cấp trình soạn thảo WYSIWYG. Nhập một thư viện như TinyMCE bằng một
duy nhất và bạn đã sẵn sàng. Trình soạn thảo WYSIWYG rất mạnh mẽ và hỗ trợ mọi loại định dạng, thậm chí áp dụng các lớp CSS vào nội dung để tạo kiểu.Nhưng TinyMCE không phải là gói hiệu quả nhất với dung lượng khoảng 500 KB sau khi thu nhỏ. Đó không phải là lời chỉ trích mà là dấu hiệu cho thấy nó bao phủ bao nhiêu chức năng. Chúng tôi muốn thứ gì đó "cơ bản" hơn thế cho mục đích đơn giản của mình. Tìm kiếm trên GitHub sẽ cho ra nhiều khả năng hơn. Tuy nhiên, các giải pháp có vẻ như thuộc một trong hai loại sau:
- Đầu vào chấp nhận văn bản thuần túy, nhưng HTML được tạo ra chỉ hỗ trợ các thẻ HTML
và
- Đầu vào chuyển đổi văn bản thuần túy thành HTML có định dạng, nhưng khi nói đến "văn bản thuần túy", công cụ này có vẻ muốn nói đến "Markdown" (hoặc một dạng nào đó). mô-đun Perl txt2html (từ năm 1994!) sẽ thuộc loại này.
Thiết lập HTML
Chúng ta sẽ bắt đầu với cấu trúc HTML cho đầu vào và đầu ra. Đối với phần tử đầu vào, có lẽ tốt nhất là chúng ta nên sử dụng
. Đối với phần tử đầu ra và kiểu dáng liên quan, có rất nhiều lựa chọn. Sau đây chỉ là một ví dụ với một số mã CSS rất cơ bản để đặt đầu vào
ở bên trái và đầu ra
ở bên phải:Xem Bút [Kiểu Biểu mẫu Cơ sở [phân nhánh]](https://codepen.io/smashingmag/pen/OJGoNOX) của Geoff Graham.
Xem Bút Kiểu Biểu mẫu Cơ sở [phân nhánh] của Geoff Graham.
Bạn có thể phát triển thêm CSS, nhưng đó không phải là trọng tâm của bài viết này. Không còn nghi ngờ gì nữa, thiết kế có thể đẹp hơn những gì tôi cung cấp ở đây!
Ghi lại đầu vào văn bản thuần túy
Chúng ta sẽ thiết lập trình xử lý sự kiệnonkeyup
trên
để gọi hàm JavaScript có tên là convert()
thực hiện những gì nó nói: chuyển đổi văn bản thuần túy thành HTML. Hàm chuyển đổi phải chấp nhận một tham số, một chuỗi, cho đầu vào văn bản thuần túy của người dùng được nhập vào phần tử
:
Mã:
onkeyup
là lựa chọn tốt hơn so với onkeydown
trong trường hợp này, vì onkeyup
sẽ gọi hàm chuyển đổi sau khi người dùng hoàn tất mỗi lần nhấn phím, trái ngược với trước khi điều đó xảy ra. Theo cách này, đầu ra, được làm mới với mỗi lần nhấn phím, luôn bao gồm ký tự được nhập gần đây nhất. Nếu chuyển đổi được kích hoạt bằng trình xử lý onkeydown
, đầu ra sẽ loại trừ ký tự gần đây nhất mà người dùng đã nhập. Điều này có thể gây khó chịu khi, ví dụ, người dùng đã nhập xong một câu nhưng vẫn chưa thấy dấu chấm câu cuối cùng, chẳng hạn như dấu chấm (.
), trong đầu ra cho đến khi nhập một ký tự khác trước. Điều này tạo ra ấn tượng về lỗi đánh máy, trục trặc hoặc độ trễ khi thực tế không có lỗi nào.Trong JavaScript, hàm
convert()
có các trách nhiệm sau:- Mã hóa đầu vào trong HTML.
- Xử lý đầu vào theo từng dòng và gói từng dòng riêng lẻ trong thẻ HTML
hoặc
- Xử lý đầu ra của các phép biến đổi dưới dạng một chuỗi duy nhất, gói URL trong thẻ HTML
và thay thế tên tệp hình ảnh bằng các phần tử
.
-
html_encode()
-
convert_text_to_HTML()
-
convert_images_and_links_to_HTML()
Mã hóa Đầu vào Thành HTML
Sử dụng hàmhtml_encode()
để mã hóa/khử trùng HTML đầu vào. Mã hóa HTML đề cập đến quá trình thoát hoặc thay thế một số ký tự nhất định trong đầu vào chuỗi để ngăn người dùng chèn HTML của riêng họ vào đầu ra. Ít nhất, chúng ta nên thay thế các ký tự sau:-
bằng
>
-
&
bằng&
-
'
bằng'
-
"
bằng"
htmlspecialchars()
, htmlentities()
và strip_tags()
. Nói như vậy, việc viết hàm riêng của chúng ta để thực hiện điều này tương đối dễ dàng, đó là những gì chúng ta sẽ sử dụng hàm html_encode()
mà chúng ta đã định nghĩa trước đó:
Mã:
function html_encode(input) { const textArea = document.createElement("textarea"); textArea.innerText = input; return textArea.innerHTML.split("
").join("\n");}
Miễn là chúng ta đang nói về chủ đề bảo mật công việc của mình, hãy đảm bảo mã hóa HTML cho đầu vào ở phía sau, nơi người dùng không thể can thiệp. Đồng thời, hãy cẩn thận không mã hóa đầu vào nhiều hơn một lần. Mã hóa văn bản đã được mã hóa HTML sẽ phá vỡ chức năng đầu ra. Cách tiếp cận tốt nhất cho lưu trữ back-end là front-end chuyển đầu vào thô, chưa mã hóa đến back-end, sau đó yêu cầu back-end mã hóa HTML đầu vào trước khi chèn vào cơ sở dữ liệu.
Điều đó nói rằng, điều này chỉ tính đến việc vệ sinh và lưu trữ đầu vào ở back-end. Chúng ta vẫn phải hiển thị đầu ra HTML được mã hóa ở front-end. Có ít nhất hai cách tiếp cận cần xem xét:
- Chuyển đổi đầu vào thành HTML sau khi mã hóa HTML và trước khi chèn vào cơ sở dữ liệu.
Cách này hiệu quả vì đầu vào chỉ cần được chuyển đổi một lần. Tuy nhiên, đây cũng là một cách tiếp cận không linh hoạt vì việc cập nhật HTML trở nên khó khăn nếu các yêu cầu đầu ra thay đổi trong tương lai. - Chỉ lưu trữ văn bản đầu vào được mã hóa HTML trong cơ sở dữ liệu và chuyển đổi động thành HTML trước khi hiển thị đầu ra cho mỗi yêu cầu nội dung.
Cách này kém hiệu quả hơn vì việc chuyển đổi sẽ diễn ra trong mỗi yêu cầu. Tuy nhiên, nó cũng linh hoạt hơn vì có thể cập nhật cách chuyển đổi văn bản đầu vào thành HTML nếu yêu cầu thay đổi.
Áp dụng Thẻ HTML Ngữ nghĩa
Chúng ta hãy sử dụng hàmconvert_text_to_HTML()
mà chúng ta đã định nghĩa trước đó để bao bọc từng dòng trong các thẻ HTML tương ứng của chúng, có thể là
hoặc
. Để xác định thẻ nào sẽ sử dụng, chúng ta sẽ chia
đầu vào văn bản trên ký tự xuống dòng (\n
) để văn bản được xử lý dưới dạng một mảng các dòng thay vì một chuỗi đơn, cho phép chúng ta đánh giá chúng riêng lẻ.
Mã:
function convert_text_to_HTML(txt) { // Biến đầu ra let out = ''; // Chia văn bản tại ký tự xuống dòng thành một mảng const txt_array = txt.split("\n"); // Lấy số dòng trong mảng const txt_array_length = txt_array.length; // Biến để theo dõi số dòng (không phải dòng trống) let non_blank_line_count = 0; for (let i = 0; i < txt_array_length; i++) { // Lấy dòng hiện tại const line = txt_array[i]; // Tiếp tục nếu một dòng không chứa ký tự văn bản if (line === ''){ continue; } non_blank_line_count++; // Nếu một dòng là dòng đầu tiên chứa văn bản if (non_blank_line_count === 1){ // ...bọc dòng văn bản trong thẻ Heading 1 out += `${line}[/HEADING]`; // ...nếu không, hãy bọc dòng văn bản trong thẻ Paragraph. } else { out += `
${line}
`; } } return out;}
vào dòng đó; nếu không, chúng ta sẽ đánh dấu nó trong thẻ
.Logic này có thể được sử dụng để tính đến các loại phần tử khác mà bạn có thể muốn đưa vào đầu ra. Ví dụ, có lẽ dòng thứ hai được coi là dòng ghi chú nêu tên tác giả và liên kết đến kho lưu trữ tất cả các bài đăng của tác giả.
Gắn thẻ URL và hình ảnh bằng biểu thức chính quy
Tiếp theo, chúng ta sẽ tạo hàmconvert_images_and_links_to_HTML()
để mã hóa URL và hình ảnh dưới dạng các phần tử HTML. Đây là một đoạn mã khá dài, vì vậy tôi sẽ đưa nó vào và chúng ta sẽ ngay lập tức bắt đầu phân tích để giải thích cách thức hoạt động của nó.
Mã:
hàm chuyển đổi_hình_ảnh_và_liên_kết_thành_HTML(chuỗi){ hãy để urls_unique = []; hãy để images_unique = []; const urls = string.match(/https*:\/\/[^\s