Bạn có đang lo lắng về thanh công cụ trình chỉnh sửa đơn điệu và thiếu tính linh hoạt không? Bạn muốn tích hợp trình chỉnh sửa với phong cách thiết kế riêng của sản phẩm? Bài viết này sẽ hướng dẫn chi tiết cách tạo thanh công cụ tùy chỉnh cho draft-js, từ cơ bản đến nâng cao, giúp bạn xây dựng giao diện trình soạn thảo chuyên nghiệp.
Cơ sở xây dựng thanh công cụ
Draft-js là framework mã nguồn mở của Facebook, cung cấp API linh hoạt để xây dựng trình soạn thảo văn bản. Thanh công cụ thực chất là tập hợp các nút điều khiển, hoạt động bằng cách gọi các phương thức từ lớp công cụ của draft-js để thay đổi trạng thái trình soạn thảo (EditorState).
Cấu trúc thành phần chính
Một thanh công cụ đầy đủ thường bao gồm hai thành phần: kiểm soát kiểu khối (BlockStyleControls) và kiểm soát kiểu nội tuyến (InlineStyleControls). Hai thành phần này nhận trạng thái trình soạn thảo qua props và kích hoạt cập nhật trạng thái khi người dùng tương tác.
Ví dụ minh họa cấu trúc thanh công cụ:
<div className="RichEditor-root">
<CustomBlockToolbar
editorState={editorState}
onStyleChange={this.handleBlockStyleChange}
/>
<CustomInlineToolbar
editorState={editorState}
onStyleChange={this.handleInlineStyleChange}
/>
<Editor
editorState={editorState}
onChange={this.handleEditorChange}
/>
</div>
Phương pháp điều khiển kiểu
Draft-js cung cấp lớp công cụ RichUtils với các phương thức toggleBlockType và toggleInlineStyle để chuyển đổi kiểu nội dung:
handleBlockStyleChange(styleType) {
this.setState({
editorState: RichUtils.toggleBlockType(
this.state.editorState,
styleType
)
});
}
handleInlineStyleChange(styleType) {
this.setState({
editorState: RichUtils.toggleInlineStyle(
this.state.editorState,
styleType
)
});
}
Thanh công cụ kiểu khối
Thanh công cụ kiểu khối được dùng để điều chỉnh định dạng cấp đoạn như tiêu đề, danh sách, khối trích dẫn...
Định nghĩa kiểu khối
Các kiểu khối phổ biến được định nghĩa như sau:
const BLOCK_TYPES = [
{label: 'Tiêu đề 1', style: 'header-one'},
{label: 'Tiêu đề 2', style: 'header-two'},
{label: 'Danh sách không đánh số', style: 'unordered-list-item'},
{label: 'Danh sách đánh số', style: 'ordered-list-item'},
{label: 'Khối mã', style: 'code-block'},
];
Thành phần điều khiển kiểu khối
Thành phần CustomBlockToolbar xác định kiểu khối hiện tại để highlight nút:
const CustomBlockToolbar = ({editorState, onStyleChange}) => {
const selection = editorState.getSelection();
const currentBlock = editorState
.getCurrentContent()
.getBlockForKey(selection.getStartKey());
return (
<div className="RichEditor-controls">
{BLOCK_TYPES.map(type => (
<StyleButton
key={type.label}
active={type.style === currentBlock.getType()}
label={type.label}
onClick={() => onStyleChange(type.style)}
/>
))}
</div>
);
};
Thanh công cụ kiểu nội tuyến
Thanh công cụ này điều khiển định dạng cấp văn bản như in đậm, in nghiêng, gạch chân...
Định nghĩa kiểu nội tuyến
Các kiểu nội tuyến phổ biến:
const INLINE_STYLES = [
{label: 'In đậm', style: 'BOLD'},
{label: 'In nghiêng', style: 'ITALIC'},
{label: 'Gạch chân', style: 'UNDERLINE'},
{label: 'Font monospace', style: 'CODE'},
];
Thành phần điều khiển kiểu nội tuyến
Thành phần CustomInlineToolbar hoạt động dựa trên kiểu nội tuyến hiện tại:
const CustomInlineToolbar = ({editorState, onStyleChange}) => {
const currentStyles = editorState.getCurrentInlineStyle();
return (
<div className="RichEditor-controls">
{INLINE_STYLES.map(type => (
<StyleButton
key={type.label}
active={currentStyles.has(type.style)}
label={type.label}
onClick={() => onStyleChange(type.style)}
/>
))}
</div>
);
};
Tối ưu giao diện và tương tác
Để tạo trải nghiệm người dùng tốt, cần tối ưu giao diện và phản hồi tương tác. CSS cơ bản trong ví dụ có thể được điều chỉnh như sau:
.RichEditor-controls {
font-family: 'Helvetica', sans-serif;
font-size: 14px;
margin-bottom: 5px;
user-select: none;
}
.RichEditor-styleButton {
color: #999;
cursor: pointer;
margin-right: 16px;
padding: 2px 0;
display: inline-block;
}
.RichEditor-styleButton.active {
color: #5890ff;
}
Kỹ thuật tùy chỉnh nâng cao
Bên cạnh các chức năng cơ bản, draft-js hỗ trợ nhiều tùy chỉnh nâng cao:
Áp dụng kiểu tùy chỉnh
Định nghĩa kiểu tùy chỉnh qua customStyleMap:
const customStyles = {
CODE: {
backgroundColor: 'rgba(0, 0, 0, 0.05)',
fontFamily: '"Inconsolata", monospace',
fontSize: 16,
padding: 2,
},
HIGHLIGHT: {
backgroundColor: 'yellow',
},
};
<Editor
customStyleMap={customStyles}
/>
Thiết kế thanh công cụ phản hồi
Điều chỉnh giao diện cho thiết bị di động:
@media (max-width: 768px) {
.RichEditor-controls {
overflow-x: auto;
padding-bottom: 5px;
}
.RichEditor-styleButton {
margin-right: 10px;
white-space: nowrap;
}
}
Tích hợp biểu tượng từ thư viện
Sử dụng Font Awesome thay cho nhãn văn bản:
const INLINE_STYLES = [
{label: <i className="fa fa-bold"></i>, style: 'BOLD'},
{label: <i className="fa fa-italic"></i>, style: 'ITALIC'},
];