Trình soạn thảo mã web trực tuyến hữu ích nhất khi bạn không có cơ hội sử dụng ứng dụng soạn thảo mã hoặc khi bạn muốn nhanh chóng dùng thử một thứ gì đó trên web bằng máy tính hoặc thậm chí là điện thoại di động. Đây cũng là một dự án thú vị để thực hiện vì việc có kiến thức về cách xây dựng trình soạn thảo mã sẽ giúp bạn có ý tưởng về cách tiếp cận các dự án khác yêu cầu bạn tích hợp trình soạn thảo mã để hiển thị một số chức năng.
Dưới đây là một số khái niệm về React mà bạn cần biết để theo dõi bài viết này:
Một API lập trình phong phú và hệ thống chủ đề CSS có sẵn để tùy chỉnh CodeMirror cho phù hợp với ứng dụng của bạn và mở rộng nó với chức năng mới. Nó cung cấp cho chúng ta chức năng tạo trình soạn thảo mã phong phú chạy trên web và hiển thị kết quả mã của chúng ta theo thời gian thực.
Trong phần tiếp theo, chúng ta sẽ thiết lập dự án React mới và cài đặt các thư viện cần thiết để xây dựng ứng dụng web của mình.
Sau khi tạo ứng dụng React mới, hãy điều hướng đến thư mục của dự án đó trong giao diện dòng lệnh:
Có hai thư viện chúng ta cần cài đặt ở đây:
Sau khi cài đặt các thư viện cần thiết cho dự án này, hãy tạo các tab và bật tính năng chuyển đổi tab giữa ba tab sẽ xuất hiện trong trình chỉnh sửa của chúng ta (dành cho HTML, CSS và JavaScript).
Tạo một thư mục có tên
Sau đây là toàn bộ mã cần thiết trong thành phần
Sau đây là giải thích đầy đủ về những gì chúng tôi đã làm ở trên:
Để theo dõi tab hoặc trình soạn thảo nào đang mở, chúng ta cần một trạng thái khai báo để giữ giá trị của trình soạn thảo đang mở. Sử dụng hook React
Đây là cách chúng ta thực hiện:
Tại đây, chúng ta đã khai báo trạng thái của mình. Trạng thái này lấy tên của trình soạn thảo hiện đang mở. Vì giá trị
Chúng ta hãy tiếp tục và viết hàm sẽ sử dụng
Lưu ý: Hai tab có thể không được mở cùng một lúc, vì vậy chúng ta sẽ phải cân nhắc điều đó khi viết hàm của mình.
Đây là hình ảnh của hàm có tên
Ở đây, chúng ta truyền một đối số hàm duy nhất, đó là tên của tab hiện đang được chọn. Đối số này sẽ được cung cấp ở bất kỳ nơi nào hàm được gọi và tên liên quan của tab đó sẽ được truyền vào.
Hãy tạo ba phiên bản của
Đây là những gì chúng tôi đã làm:
Chúng ta hãy xem lại đoạn mã trên bằng tiếng Anh thông thường. Nếu giá trị của
Chúng ta đã sử dụng thẻ đoạn văn (
Chúng ta đã đi được đến đây rồi! Khi nhấp vào một nút, nó sẽ kích hoạt hành động đặt tab mà nó đại diện thành

Ảnh GIF hiển thị nút chuyển đổi tab hiện tại của chúng tôi. (Xem trước lớn)
Hãy thêm một chút CSS vào vùng chứa
Hãy nhớ rằng chúng ta đã thêm

(Xem trước lớn)
Hãy tự hào về những gì bạn đã làm để đạt được thành quả như ngày hôm nay. Trong phần tiếp theo, chúng ta sẽ tạo trình soạn thảo, thay thế các thẻ
Đây là những gì chúng tôi đã làm:
Hãy sử dụng
Chúng ta hãy cùng xem qua những gì chúng ta đã làm ở đây, giải thích một số thuật ngữ CodeMirror.
Các chế độ CodeMirror chỉ định ngôn ngữ mà trình soạn thảo dành cho. Chúng tôi đã nhập ba chế độ vì chúng tôi có ba trình soạn thảo cho dự án này:
Tiếp theo, chúng ta hãy thảo luận về những thứ trong
Trình xử lý
Chúng ta chỉ cần
Tiếp theo, chúng ta sẽ thêm một menu thả xuống cho phép chúng ta chọn các chủ đề khác nhau cho trình soạn thảo. Vì vậy, hãy xem các chủ đề trong CodeMirror.
Đầu tiên, hãy nhập các chủ đề của chúng tôi vào thành phần
Tiếp theo, tạo một mảng chứa tất cả các chủ đề mà chúng ta đã nhập:
Hãy khai báo một hook
Hãy tạo menu thả xuống:
Trong mã trên, chúng tôi đã sử dụng thẻ HTML
Vì chúng ta cần điền tên chủ đề vào menu thả xuống trong
Khoan đã — chúng ta chưa giải thích xong đoạn mã trên. Trong thẻ mở
Tại thời điểm này, chúng ta đã tạo menu thả xuống, thiết lập trạng thái của chủ đề và viết hàm để đặt trạng thái với giá trị mới. Điều cuối cùng chúng ta cần làm để CodeMirror sử dụng chủ đề của chúng ta là truyền chủ đề cho đối tượng
Dưới đây là giao diện của
Bây giờ, chúng ta đã tạo một danh sách thả xuống các chủ đề khác nhau có thể được chọn trong trình chỉnh sửa.
Dưới đây là giao diện của toàn bộ mã trong
Chỉ có một
Bây giờ trình chỉnh sửa của chúng ta đã sẵn sàng, hãy quay lại
Trong
Nếu bạn nhớ lại, chúng ta sẽ cần sử dụng các trạng thái này để giữ và cung cấp nội dung cho trình soạn thảo của mình.
Tiếp theo, hãy thay thế các thẻ đoạn văn (
Nếu bạn đã theo dõi cho đến bây giờ, bạn sẽ hiểu những gì chúng tôi đã làm trong khối mã ở trên.
Đây là bản tiếng Anh đơn giản: Chúng tôi đã thay thế các thẻ
Chúng tôi đã tiến xa đến vậy! Đây là giao diện ứng dụng của chúng tôi hiện tại:

(Xem trước lớn)
Theo MDN:
Tại đây, chúng ta đã tạo iframe và chứa nó trong thẻ chứa
Bây giờ chúng ta đã tạo trạng thái, việc tiếp theo cần làm là hiển thị kết quả trong trạng thái bất cứ khi nào chúng ta nhập vào trình soạn thảo mã. Nhưng điều chúng ta không muốn là phải render lại thành phần sau mỗi lần nhấn phím. Với suy nghĩ đó, chúng ta hãy tiến hành.
Đầu tiên, hãy nhập hook
Hãy viết
Ở đây, chúng ta đã viết một hook
Tại sao chúng ta cần sử dụng
Điều tiếp theo chúng ta đã làm ở trên là cập nhật
Lưu ý rằng khi thiết lập
Câu lệnh
Dưới đây là giao diện của dự án của chúng tôi hiện tại:

(Xem trước lớn)
Điều đầu tiên cần làm là nhập tiện ích bổ sung cho mục đích này vào tệp
Chúng ta hãy truyền nó vào các tùy chọn
Đây là những gì chúng ta có:

(Xem trước lớn)
Bạn có thể thêm nhiều tiện ích bổ sung này vào trình chỉnh sửa của mình để cung cấp cho nó các tính năng phong phú hơn. Chúng tôi không thể xem xét tất cả các tính năng đó ở đây.
Bây giờ chúng ta đã hoàn thành việc này, hãy thảo luận ngắn gọn về những điều chúng ta có thể làm để cải thiện khả năng truy cập và hiệu suất của ứng dụng.
Vì chúng tôi chủ yếu chú ý đến chức năng, nên chúng tôi có thể đã bỏ qua một chút thiết kế. Để có khả năng truy cập tốt hơn, đây là một số điều bạn có thể làm để cải thiện giải pháp này:
Shedrack đã làm rất tốt khi giải thích các phương pháp cải thiện và tối ưu hóa hiệu suất trong các ứng dụng React. Rất đáng để xem!
Xem thêm tại đây
Dưới đây là một số khái niệm về React mà bạn cần biết để theo dõi bài viết này:
- Móc,
- Cấu trúc thành phần,
- Thành phần chức năng,
- Đạo cụ.
Sử dụng CodeMirror
Chúng ta sẽ sử dụng một thư viện có tên là CodeMirror để xây dựng trình soạn thảo của mình. CodeMirror là một trình soạn thảo văn bản đa năng được triển khai bằng JavaScript cho trình duyệt. Nó dành riêng cho việc chỉnh sửa mã và đi kèm với một số chế độ ngôn ngữ và tiện ích bổ sung để có chức năng chỉnh sửa nâng cao hơn.Một API lập trình phong phú và hệ thống chủ đề CSS có sẵn để tùy chỉnh CodeMirror cho phù hợp với ứng dụng của bạn và mở rộng nó với chức năng mới. Nó cung cấp cho chúng ta chức năng tạo trình soạn thảo mã phong phú chạy trên web và hiển thị kết quả mã của chúng ta theo thời gian thực.
Trong phần tiếp theo, chúng ta sẽ thiết lập dự án React mới và cài đặt các thư viện cần thiết để xây dựng ứng dụng web của mình.
Tạo dự án React mới
Chúng ta hãy bắt đầu bằng cách tạo một dự án React mới. Trong giao diện dòng lệnh, hãy điều hướng đến thư mục mà bạn muốn tạo dự án của mình và tạo một ứng dụng React và đặt tên làcode_editor
:
Mã:
npx create-react-app code_editor
Mã:
cd code_editor
codemirror
và react-codemirror2
.
Mã:
npm install codemirror react-codemirror2
Thành phần nút
Thay vì tạo các nút riêng lẻ, hãy biến nút thành một thành phần có thể tái sử dụng. Trong dự án của chúng ta, nút sẽ có ba phiên bản, theo ba tab chúng ta cần.Tạo một thư mục có tên
components
trong thư mục src
. Trong thư mục components
mới này, hãy tạo một tệp JSX có tên Button.jsx
.Sau đây là toàn bộ mã cần thiết trong thành phần
Button
:
Mã:
import React from 'react'const Button = ({title, onClick}) => { return ( {title} )}export default Button
- Chúng tôi đã tạo một thành phần chức năng có tên là
Button
, sau đó chúng tôi đã xuất thành phần này. - Chúng tôi đã hủy cấu trúc
title
vàonClick
khỏi các thuộc tính đi vào thành phần. Tại đây,title
sẽ là một chuỗi văn bản vàonClick
sẽ là một hàm được gọi khi nhấp vào nút. - Tiếp theo, chúng ta sử dụng phần tử
button
để khai báo nút của mình và sử dụng các thuộc tínhstyle
để tạo kiểu cho nút sao cho đẹp mắt. - Chúng ta đã thêm thuộc tính
onClick
và truyền các thuộc tính hàmonClick
đã phi cấu trúc vào đó. - Điều cuối cùng bạn sẽ nhận thấy chúng ta đã làm trong thành phần này là truyền vào
{title}
làm nội dung của thẻbutton
. Điều này cho phép chúng ta hiển thị tiêu đề một cách động, dựa trên prop nào được truyền cho phiên bản của thành phần nút khi nó được gọi.
App.js.
Truy cập App.js
và nhập thành phần nút mới tạo:
Mã:
import Button from './components/Button';
useState
, chúng ta sẽ thiết lập trạng thái sẽ lưu trữ tên của tab trình soạn thảo hiện đang mở khi nhấp vào nút của tab đó.Đây là cách chúng ta thực hiện:
Mã:
import React, { useState } from 'react';import './App.css';import Button from './components/Button';function App() { const [openedEditor, setOpenedEditor] = useState('html'); return ( );}export default App;
html
được truyền làm giá trị mặc định của trạng thái, nên trình soạn thảo HTML sẽ là tab mở theo mặc định.Chúng ta hãy tiếp tục và viết hàm sẽ sử dụng
setOpenedEditor
để thay đổi giá trị của trạng thái khi nhấp vào nút tab.Lưu ý: Hai tab có thể không được mở cùng một lúc, vì vậy chúng ta sẽ phải cân nhắc điều đó khi viết hàm của mình.
Đây là hình ảnh của hàm có tên
onTabClick
của chúng ta:
Mã:
import React, { useState } from 'react';import './App.css';import Button from './components/Button';function App() { ... const onTabClick = (editorName) => { setOpenedEditor(editorName); }; return ( );}export default App;
Hãy tạo ba phiên bản của
Button
cho ba tab mà chúng ta cần:
Mã:
Chào mừng đến với trình chỉnh sửa!
{ onTabClick('html') }} /> { onTabClick('css') }} /> { onTabClick('js') }} />
- Chúng tôi bắt đầu bằng cách thêm thẻ
p
, về cơ bản chỉ để cung cấp một số ngữ cảnh cho nội dung ứng dụng của chúng tôi. - Chúng tôi đã sử dụng thẻ
div
để bao bọc các nút tab của mình. Thẻdiv
mang mộtclassName
mà chúng tôi sẽ sử dụng để định kiểu các nút thành dạng lưới hiển thị trong tệp CSS sau trong hướng dẫn này. - Tiếp theo, chúng tôi đã khai báo ba phiên bản của thành phần
Button
. Nếu bạn nhớ lại, thành phầnButton
có hai thuộc tính,title
vàonClick
. Trong mọi trường hợp của thành phầnButton
, hai prop này đều được cung cấp. - Property
title
lấy tiêu đề của tab. - Property
onClick
lấy một hàm,onTabClick
, mà chúng ta vừa tạo và lấy một đối số duy nhất: tên của tab được chọn.
openedEditor
được đặt thành html
(tức là setOpenedEditor('html')
), thì tab cho phần HTML sẽ trở thành tab hiện đang hiển thị. Bạn sẽ hiểu rõ hơn khi chúng tôi thực hiện bên dưới:
Mã:
...return ( ... { openedEditor === 'html' ? (
Trình chỉnh sửa html đang mở
) : openedEditor === 'css' ? (
Trình chỉnh sửa CSS đang mở!!!!!!
) : (
Trình chỉnh sửa JavaScript đang mở
) } );...
openedEditor
là html
, thì hãy hiển thị phần HTML. Nếu không, nếu giá trị của openedEditor
là css
, thì hiển thị phần CSS. Nếu không, nếu giá trị không phải là html
cũng không phải css
, thì điều đó có nghĩa là giá trị phải là js
, vì chúng ta chỉ có ba giá trị có thể cho trạng thái openedEditor
; do đó, khi đó chúng ta sẽ hiển thị tab cho JavaScript.Chúng ta đã sử dụng thẻ đoạn văn (
p
) cho các phần khác nhau trong các điều kiện toán tử ba ngôi. Khi tiến hành, chúng ta sẽ tạo các thành phần trình soạn thảo và thay thế các thẻ p
bằng chính các thành phần trình soạn thảo.Chúng ta đã đi được đến đây rồi! Khi nhấp vào một nút, nó sẽ kích hoạt hành động đặt tab mà nó đại diện thành
true
, làm cho tab đó hiển thị. Đây là giao diện hiện tại của ứng dụng:
Ảnh GIF hiển thị nút chuyển đổi tab hiện tại của chúng tôi. (Xem trước lớn)
Hãy thêm một chút CSS vào vùng chứa
div
chứa các nút. Chúng ta muốn các nút được hiển thị theo dạng lưới, thay vì xếp chồng theo chiều dọc như trong hình ảnh ở trên. Hãy đi đến tệp App.css
của bạn và thêm mã sau:
Mã:
.tab-button-container{ display: flex;}
className="tab-button-container"
làm thuộc tính trong thẻ div
chứa các nút ba tab. Ở đây, chúng ta đã định kiểu cho vùng chứa đó, sử dụng CSS để đặt chế độ hiển thị của nó thành flex
. Đây là kết quả:
(Xem trước lớn)
Hãy tự hào về những gì bạn đã làm để đạt được thành quả như ngày hôm nay. Trong phần tiếp theo, chúng ta sẽ tạo trình soạn thảo, thay thế các thẻ
p
bằng chúng.Tạo trình soạn thảo
Vì chúng ta đã cài đặt các thư viện mà chúng ta sẽ làm việc trong trình soạn thảo CodeMirror, chúng ta hãy tiếp tục và tạo tệpEditor.jsx
của chúng ta trong thư mục components
.components > Editor.jsx
Sau khi tạo tệp mới, chúng ta hãy viết một số mã ban đầu vào đó:
Mã:
import React, { useState } from 'react';import 'codemirror/lib/codemirror.css';import { Controlled as ControlledEditorComponent } from 'react-codemirror2';const Editor = ({ language, value, setEditorState }) => { return ( )}export default Editor
- Chúng tôi đã nhập React cùng với hook
useState
vì chúng tôi sẽ cần nó. - Chúng tôi đã nhập tệp CSS CodeMirror (có nguồn gốc từ thư viện CodeMirror mà chúng tôi đã cài đặt, vì vậy bạn không cần phải cài đặt theo bất kỳ cách đặc biệt nào).
- Chúng tôi đã nhập
Controlled
từreact-codemirror2
, đổi tên thànhControlledEditorComponent
để rõ ràng hơn. Chúng ta sẽ sử dụng nó trong thời gian ngắn. - Sau đó, chúng ta khai báo thành phần chức năng
Editor
và chúng ta có một câu lệnh return vớidiv
rỗng, vớiclassName
trong câu lệnh return hiện tại.
language
, value
và setEditorState
. Ba prop này sẽ được cung cấp trong bất kỳ phiên bản nào của trình soạn thảo khi nó được gọi trong App.js
.Hãy sử dụng
ControlledEditorComponent
để viết mã cho trình soạn thảo của chúng ta. Sau đây là những gì chúng ta sẽ làm:
Mã:
import React, { useState } from 'react';import 'codemirror/lib/codemirror.css';import 'codemirror/mode/xml/xml';import 'codemirror/mode/javascript/javascript';import 'codemirror/mode/css/css';import { Controlled as ControlledEditorComponent } from 'react-codemirror2';const Editor = ({ language, value, setEditorState }) => { return ( )}export default Editor
Các chế độ CodeMirror chỉ định ngôn ngữ mà trình soạn thảo dành cho. Chúng tôi đã nhập ba chế độ vì chúng tôi có ba trình soạn thảo cho dự án này:
- XML: Chế độ này dành cho HTML. Nó sử dụng thuật ngữ XML.
- JavaScript: Điều này (
codemirror/mode/javascript/javascript
) đưa vào chế độ JavaScript. - CSS: Điều này (
codemirror/mode/css/css
) đưa vào chế độ CSS.
language
mà chúng ta đã hủy cấu trúc. Nhưng điều này không thay đổi thực tế là các chế độ cần được nhập để hoạt động.Tiếp theo, chúng ta hãy thảo luận về những thứ trong
ControlledEditorComponent
:-
onBeforeChange
Điều này được gọi bất cứ khi nào bạn ghi vào hoặc xóa khỏi trình soạn thảo. Hãy nghĩ về điều này giống như trình xử lýonChange
mà bạn thường có trong trường nhập để theo dõi các thay đổi. Sử dụng điều này, chúng ta sẽ có thể lấy giá trị của trình soạn thảo bất cứ khi nào có thay đổi mới và lưu nó vào trạng thái của trình soạn thảo. Chúng ta sẽ viết hàm{handleChange}
khi chúng ta tiến hành. -
value = {value}
Đây chỉ là nội dung của trình soạn thảo tại bất kỳ thời điểm nào. Chúng tôi đã truyền một prop không có cấu trúc có tên làvalue
cho thuộc tính này. Propvalue
là trạng thái giữ giá trị của trình soạn thảo đó. Giá trị này sẽ được cung cấp từ phiên bản của trình soạn thảo. -
className
="code-mirror-wrapper"
Tên lớp này không phải là kiểu mà chúng tôi tự tạo. Nó được cung cấp từ tệp CSS của CodeMirror, tệp mà chúng tôi đã nhập ở trên. -
options
Đây là một đối tượng có các chức năng khác nhau mà chúng tôi muốn trình soạn thảo của mình có. Có nhiều tùy chọn tuyệt vời trong CodeMirror. Hãy xem những cái chúng ta đã sử dụng ở đây:lineWrapping: true
Điều này có nghĩa là mã sẽ ngắt dòng xuống dòng tiếp theo khi dòng đó đầy. -
lint: true
Điều này cho phép kiểm tra lỗi. -
mode: language
Chế độ này, như đã thảo luận ở trên, sẽ sử dụng ngôn ngữ mà trình soạn thảo sẽ sử dụng. Ngôn ngữ đã được nhập ở trên, nhưng trình soạn thảo sẽ áp dụng ngôn ngữ dựa trên giá trịlanguage
được cung cấp cho trình soạn thảo thông qua prop. -
lineNumbers: true
Điều này chỉ định rằng trình soạn thảo phải có số dòng cho mỗi dòng.
handleChange
cho trình xử lý onBeforeChange
:
Mã:
const handleChange = (editor, data, value) => { setEditorState(value);}
onBeforeChange
cung cấp cho chúng ta quyền truy cập vào ba thứ: editor, data, value
.Chúng ta chỉ cần
value
vì đó là thứ chúng ta muốn truyền vào prop setEditorState
của mình. Prop setEditorState
biểu thị giá trị được đặt cho mỗi trạng thái mà chúng ta đã khai báo trong App.js
, giữ giá trị cho mỗi trình soạn thảo. Khi tiếp tục, chúng ta sẽ xem cách truyền giá trị này dưới dạng prop cho thành phần Editor
.Tiếp theo, chúng ta sẽ thêm một menu thả xuống cho phép chúng ta chọn các chủ đề khác nhau cho trình soạn thảo. Vì vậy, hãy xem các chủ đề trong CodeMirror.
Chủ đề CodeMirror
CodeMirror có nhiều chủ đề mà chúng ta có thể chọn. Truy cập trang web chính thức để xem bản demo của các chủ đề khác nhau có sẵn. Hãy tạo một danh sách thả xuống với các chủ đề khác nhau mà người dùng có thể chọn trong trình chỉnh sửa của chúng tôi. Đối với hướng dẫn này, chúng tôi sẽ thêm năm chủ đề, nhưng bạn có thể thêm bao nhiêu tùy thích.Đầu tiên, hãy nhập các chủ đề của chúng tôi vào thành phần
Editor.js
:
Mã:
import 'codemirror/theme/dracula.css';import 'codemirror/theme/material.css';import 'codemirror/theme/mdn-like.css';import 'codemirror/theme/the-matrix.css';import 'codemirror/theme/the-matrix.css';import 'codemirror/theme/night.css';
Mã:
const themeArray = ['dracula', 'material', 'mdn-like', 'the-matrix', 'night']
useState
để giữ giá trị của chủ đề đã chọn và đặt chủ đề mặc định là dracula
:
Mã:
const [theme, setTheme] = useState("dracula")
Mã:
...return ( Chọn một chủ đề: { setTheme(el.target.value) }}> { themeArray.map( theme => ( {theme} )) } // phần còn lại của mã nằm bên dưới... )...
label
để thêm nhãn vào danh sách thả xuống của mình, sau đó thêm thẻ HTML select
để tạo danh sách thả xuống của chúng tôi. Thẻ option
trong phần tử select
xác định các tùy chọn có sẵn trong danh sách thả xuống.Vì chúng ta cần điền tên chủ đề vào menu thả xuống trong
themeArray
mà chúng ta đã tạo, nên chúng ta đã sử dụng phương thức mảng .map
để ánh xạ themeArray
và hiển thị từng tên riêng lẻ bằng thẻ option
.Khoan đã — chúng ta chưa giải thích xong đoạn mã trên. Trong thẻ mở
select
, chúng ta đã truyền thuộc tính onChange
để theo dõi và cập nhật trạng thái theme
bất cứ khi nào một giá trị mới được chọn trong menu thả xuống. Bất cứ khi nào một tùy chọn mới được chọn trong menu thả xuống, giá trị sẽ được lấy từ đối tượng trả về cho chúng ta. Tiếp theo, chúng ta sử dụng setTheme
từ móc trạng thái của mình để đặt giá trị mới thành giá trị mà trạng thái giữ.Tại thời điểm này, chúng ta đã tạo menu thả xuống, thiết lập trạng thái của chủ đề và viết hàm để đặt trạng thái với giá trị mới. Điều cuối cùng chúng ta cần làm để CodeMirror sử dụng chủ đề của chúng ta là truyền chủ đề cho đối tượng
options
trong ControlledEditorComponent
. Trong đối tượng options
, hãy thêm một giá trị có tên là theme
và đặt giá trị của nó thành giá trị của trạng thái cho chủ đề đã chọn, cũng có tên là theme
.Dưới đây là giao diện của
ControlledEditorComponent
hiện tại:
Mã:
Dưới đây là giao diện của toàn bộ mã trong
Editor.js
tại thời điểm này:
Mã:
import React, { useState } từ 'react';import 'codemirror/lib/codemirror.css';import 'codemirror/theme/dracula.css';import 'codemirror/theme/material.css';import 'codemirror/theme/mdn-like.css';import 'codemirror/theme/the-matrix.css';import 'codemirror/theme/night.css';import 'codemirror/mode/xml/xml';import 'codemirror/mode/javascript/javascript';import 'codemirror/mode/css/css';import { Được kiểm soát dưới dạng ControlledEditorComponent } từ 'react-codemirror2';const Editor = ({ ngôn ngữ, giá trị, setEditorState }) => { const [chủ đề, setTheme] = useState("dracula") const handleChange = (trình soạn thảo, dữ liệu, giá trị) => { setEditorState(giá trị); } const themeArray = ['dracula', 'material', 'mdn-like', 'the-matrix', 'night'] return ( Chọn một chủ đề: { setTheme(el.target.value) }}> { themeArray.map( theme => ( {theme} )) } )}export default Editor
className
mà chúng ta cần định kiểu. Đi tới App.css
và thêm kiểu sau:
Mã:
.editor-container{ padding-top: 0.4%;}
App.js
và sử dụng chúng ở đó.src > App.js
Điều đầu tiên chúng ta cần làm là nhập thành phầnEditor.js
vào đây:
Mã:
import Editor from './components/Editor';
App.js
, hãy khai báo các trạng thái sẽ chứa nội dung của trình soạn thảo HTML, CSS và JavaScript tương ứng.
Mã:
const [html, setHtml] = useState('');const [css, setCss] = useState('');const [js, setJs] = useState('');
Tiếp theo, hãy thay thế các thẻ đoạn văn (
p
) mà chúng ta đã sử dụng cho HTML, CSS và JavaScript trong các kết xuất có điều kiện bằng các thành phần trình soạn thảo mà chúng ta vừa tạo và chúng ta cũng sẽ truyền thuộc tính thích hợp vào từng phiên bản của thành phần trình soạn thảo:
Mã:
function App() { ... return (
Welcome to the edior
// Đây là nơi chứa các nút tab... { htmlEditorIsOpen ? ( ) : cssEditorIsOpen ? ( ) : ( ) } );}xuất ứng dụng mặc định;
Đây là bản tiếng Anh đơn giản: Chúng tôi đã thay thế các thẻ
p
(có ở đó như các trình giữ chỗ) bằng các phiên bản của các thành phần trình chỉnh sửa. Sau đó, chúng tôi cung cấp các thuộc tính language
, value
và setEditorState
của chúng tương ứng để khớp với các trạng thái tương ứng của chúng.Chúng tôi đã tiến xa đến vậy! Đây là giao diện ứng dụng của chúng tôi hiện tại:

(Xem trước lớn)
Giới thiệu về Iframe
Chúng ta sẽ sử dụng khung nội tuyến (iframe) để hiển thị kết quả của mã được nhập vào trình chỉnh sửa.Theo MDN:
Phần tử Khung nội tuyến HTML () biểu diễn một browsing context lồng nhau, nhúng một trang HTML khác vào trang hiện tại.
Iframe hoạt động như thế nào trong React
Iframe thường được sử dụng với HTML thuần túy. Sử dụng Iframe với React không yêu cầu nhiều thay đổi, thay đổi chính là chuyển đổi tên thuộc tính sang camelcase. Một ví dụ về điều này làsrcdoc
sẽ trở thành srcDoc
.Tương lai của Iframe trên Web
Iframe tiếp tục thực sự hữu ích trong phát triển web. Một thứ bạn có thể muốn xem là Cổng thông tin. Như Daniel Brain giải thích:Một trong những điều mà Portals cố gắng giải quyết là vấn đề thanh URL. Khi sử dụng iframe, các thành phần được hiển thị trong iframe không mang một URL duy nhất trong thanh địa chỉ; do đó, điều này có thể không tốt cho trải nghiệm của người dùng, tùy thuộc vào trường hợp sử dụng. Portals đáng để xem qua và tôi khuyên bạn nên làm vậy, nhưng vì nó không phải là trọng tâm của bài viết này nên đây là tất cả những gì tôi sẽ nói về nó ở đây.“Portals giới thiệu một bộ khả năng mới mạnh mẽ vào hỗn hợp này. Bây giờ, có thể xây dựng thứ gì đó giống như iframe, có thể hoạt hình và biến đổi liền mạch và chiếm toàn bộ cửa sổ trình duyệt.”
Tạo Iframe để chứa kết quả của chúng ta
Chúng ta hãy tiếp tục với hướng dẫn của mình bằng cách tạo một iframe để chứa kết quả của trình chỉnh sửa.
Mã:
return ( // ... );
div
. Trong iframe, chúng ta đã truyền một số thuộc tính mà chúng ta cần:-
srcDoc
Thuộc tínhsrcDoc
được viết theo kiểu camelcase vì đây là cách viết các thuộc tính iframe trong React. Khi sử dụng iframe, chúng ta có thể nhúng một trang web bên ngoài vào trang hoặc hiển thị nội dung HTML đã chỉ định. Để tải và nhúng một trang bên ngoài, chúng ta sẽ sử dụng thuộc tínhsrc
thay thế. Trong trường hợp của chúng ta, chúng ta không tải một trang bên ngoài; thay vào đó, chúng ta muốn tạo một tài liệu HTML nội bộ mới chứa kết quả của chúng ta; đối với điều này, chúng ta cần thuộc tínhsrcDoc
. Thuộc tính này lấy tài liệu HTML mà chúng ta muốn nhúng (chúng ta chưa tạo tài liệu đó, nhưng chúng ta sẽ sớm tạo). -
title
Thuộc tính title được sử dụng để mô tả nội dung của khung nội tuyến. -
sandbox
Thuộc tính này có nhiều mục đích. Trong trường hợp của chúng ta, chúng ta đang sử dụng nó để cho phép các tập lệnh chạy trong iframe của chúng ta với giá trịallow-scripts
. Vì chúng ta đang làm việc với trình soạn thảo JavaScript, nên điều này sẽ nhanh chóng trở nên hữu ích. -
frameBorder
Điều này chỉ xác định độ dày đường viền của iframe. -
width
vàheight
Điều này xác định chiều rộng và chiều cao của iframe.
srcDoc
. Nếu bạn xem kỹ khối mã ở trên, bạn sẽ thấy rằng chúng ta đã truyền một giá trị cho thuộc tính srcDoc
: srcDoc
={srcDoc}
. Hãy sử dụng hook React useState()
của chúng ta để khai báo trạng thái srcDoc
. Để thực hiện việc này, trong tệp App.js
, hãy đến nơi chúng ta đã định nghĩa các trạng thái khác và thêm trạng thái này:
Mã:
const [srcDoc, setSrcDoc] = useState(` `);
Cấu hình Iframe để Hiển thị Kết quả
Mỗi khi có thay đổi trong bất kỳ trình soạn thảo nào cho HTML, CSS và JavaScript, chúng ta muốnuseEffect()
được kích hoạt và điều đó sẽ render kết quả đã cập nhật trong iframe. Hãy viết useEffect()
để thực hiện việc này trong tệp App.js
:Đầu tiên, hãy nhập hook
useEffect()
:
Mã:
import React, { useState, useEffect } from 'react';
useEffect()
như sau:
Mã:
useEffect(() => { const timeOut = setTimeout(() => { setSrcDoc( ` ${html} ${css} ${js} ` ) }, 250); return () => clearTimeout(timeOut) }, [html, css, js])
useEffect()
sẽ luôn chạy bất cứ khi nào giá trị trạng thái mà chúng ta đã khai báo cho trình soạn thảo HTML, CSS và JavaScript bị thay đổi hoặc cập nhật.Tại sao chúng ta cần sử dụng
setTimeout()
? Vâng, nếu chúng ta viết điều này mà không có nó, thì mỗi lần nhấn một phím trong trình soạn thảo, iframe của chúng ta sẽ được cập nhật và điều đó nói chung không tốt cho hiệu suất. Vì vậy, chúng ta sử dụng setTimeout()
để trì hoãn bản cập nhật trong 250 mili giây, cho chúng ta đủ thời gian để biết liệu người dùng có vẫn đang nhập hay không. Nghĩa là, mỗi lần người dùng nhấn một phím, nó sẽ khởi động lại số đếm, vì vậy iframe sẽ chỉ được cập nhật khi người dùng không làm gì (không nhập) trong 250 mili giây. Đây là một cách tuyệt vời để tránh phải cập nhật iframe mỗi khi nhấn một phím.Điều tiếp theo chúng ta đã làm ở trên là cập nhật
srcDoc
bằng những thay đổi mới. Thành phần srcDoc
, như chúng ta đã giải thích ở trên, sẽ hiển thị nội dung HTML đã chỉ định trong iframe. Trong mã của chúng ta, chúng ta đã truyền một mẫu HTML, lấy trạng thái html
chứa mã mà người dùng đã nhập vào trình soạn thảo HTML và đặt nó giữa các thẻ body
của mẫu của chúng ta. Chúng ta cũng lấy trạng thái css
chứa các kiểu mà người dùng đã nhập vào trình soạn thảo CSS và chúng ta đã truyền nó giữa các thẻ style
. Cuối cùng, chúng tôi lấy trạng thái js
chứa mã JavaScript mà người dùng đã nhập vào trình soạn thảo JavaScript và chúng tôi chuyển nó giữa các thẻ script
.Lưu ý rằng khi thiết lập
setSrcDoc
, chúng tôi đã sử dụng dấu ngoặc kép ngược (` `
) thay vì dấu ngoặc kép thông thường (' '
). Điều này là do dấu ngoặc kép ngược cho phép chúng tôi chuyển vào các giá trị trạng thái tương ứng, như chúng tôi đã làm trong mã ở trên.Câu lệnh
return
trong hook useEffect()
là một hàm dọn dẹp xóa setTimeout()
khi hoàn tất, để tránh rò rỉ bộ nhớ. tài liệu có thêm thông tin về useEffect
.Dưới đây là giao diện của dự án của chúng tôi hiện tại:

(Xem trước lớn)
CodeMirror Tiện ích bổ sung
Với tiện ích bổ sung CodeMirror, chúng ta có thể cải thiện trình soạn thảo của mình với nhiều chức năng hơn mà chúng ta có thể tìm thấy trong các trình soạn thảo mã khác. Hãy cùng xem qua một ví dụ về thẻ đóng được tự động thêm vào khi thẻ mở được nhập và một ví dụ khác về dấu ngoặc tự động đóng khi dấu ngoặc mở được nhập:Điều đầu tiên cần làm là nhập tiện ích bổ sung cho mục đích này vào tệp
App.js
của chúng ta:
Mã:
nhập 'codemirror/addon/edit/closetag';import 'codemirror/addon/edit/closebrackets';
ControlledEditorComponent
:
Mã:

(Xem trước lớn)
Bạn có thể thêm nhiều tiện ích bổ sung này vào trình chỉnh sửa của mình để cung cấp cho nó các tính năng phong phú hơn. Chúng tôi không thể xem xét tất cả các tính năng đó ở đây.
Bây giờ chúng ta đã hoàn thành việc này, hãy thảo luận ngắn gọn về những điều chúng ta có thể làm để cải thiện khả năng truy cập và hiệu suất của ứng dụng.
Hiệu suất và khả năng truy cập của giải pháp
Khi xem trình soạn thảo mã web của chúng tôi, một số điều chắc chắn có thể được cải thiện.Vì chúng tôi chủ yếu chú ý đến chức năng, nên chúng tôi có thể đã bỏ qua một chút thiết kế. Để có khả năng truy cập tốt hơn, đây là một số điều bạn có thể làm để cải thiện giải pháp này:
- Bạn có thể đặt một lớp
hoạt động
trên nút cho trình soạn thảo hiện đang mở. Việc làm nổi bật nút sẽ cải thiện khả năng truy cập bằng cách cung cấp cho người dùng chỉ báo rõ ràng về trình soạn thảo mà họ hiện đang làm việc. - Bạn có thể muốn trình soạn thảo chiếm nhiều không gian màn hình hơn những gì chúng ta có ở đây. Một điều khác bạn có thể thử là làm cho iframe bật lên khi nhấp vào nút được neo ở đâu đó bên cạnh. Làm như vậy sẽ cung cấp cho trình chỉnh sửa nhiều không gian màn hình hơn.
- Loại trình chỉnh sửa này sẽ hữu ích cho những người muốn chạy bài tập nhanh trên thiết bị di động của họ, vì vậy việc điều chỉnh hoàn toàn cho thiết bị di động là cần thiết (chưa kể đến cả hai điểm về thiết bị di động ở trên).
- Hiện tại, chúng tôi có thể chuyển đổi chủ đề của thành phần trình chỉnh sửa từ nhiều chủ đề mà chúng tôi đã tải vào, nhưng chủ đề chung của trang vẫn giữ nguyên. Bạn có thể cho phép người dùng chuyển đổi giữa chủ đề tối và sáng cho toàn bộ bố cục. Điều này sẽ tốt cho khả năng truy cập, giúp giảm bớt sự căng thẳng cho mắt của mọi người khi nhìn vào màn hình sáng quá lâu.
- Chúng tôi đã không xem xét các vấn đề bảo mật với iframe của mình, chủ yếu là vì chúng tôi đang tải một tài liệu HTML nội bộ trong iframe, chứ không phải một tài liệu bên ngoài. Vì vậy, chúng ta không cần cân nhắc quá kỹ điều này vì iframe phù hợp với trường hợp sử dụng của chúng ta.
- Với iframe, một cân nhắc khác sẽ là thời gian tải trang, vì nội dung được tải trong iframe thường nằm ngoài tầm kiểm soát của bạn. Trong ứng dụng của chúng tôi, đây không phải là vấn đề vì nội dung iframe của chúng tôi không phải là nội dung bên ngoài.
Shedrack đã làm rất tốt khi giải thích các phương pháp cải thiện và tối ưu hóa hiệu suất trong các ứng dụng React. Rất đáng để xem!
Kết luận
Làm việc thông qua các dự án khác nhau giúp chúng tôi tìm hiểu về nhiều chủ đề khác nhau. Bây giờ bạn đã đọc hết bài viết này, hãy thoải mái mở rộng trải nghiệm của mình bằng cách thử nghiệm thêm nhiều tiện ích bổ sung để làm cho trình soạn thảo mã phong phú hơn, cải tiến giao diện người dùng và khắc phục các vấn đề về khả năng truy cập và hiệu suất được nêu ở trên.- Toàn bộ cơ sở mã cho dự án này có sẵn trên GitHub ..
Xem thêm tại đây
Liên kết và Tài liệu
- “Cổng thông tin của Google Chrome: Giống như Iframe, nhưng tốt hơn và tệ hơn”, Daniel Brain
- “Tối ưu hóa hiệu suất”, Tài liệu React
- “Hướng dẫn sử dụng và hướng dẫn tham khảo”, Tài liệu CodeMirror