Tùy chỉnh thanh công cụ draft-js: Xây dựng giao diện trình chỉnh sửa chuyên nghiệp

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'},
];

Thẻ: draft-js react RichUtils 富文本编辑器 自定义工具栏

Đăng vào ngày 6 tháng 6 lúc 02:45