+1

Tinymce - thư viện TextEditor so “powerful”, bản free rất cháy và dễ cài đặt

TinyMCE là một trong những thư viện TextEditor mạnh mẽ và phổ biến nhất hiện nay, đặc biệt trong các ứng dụng web. Đối tượng sử dụng ở đây là những dev muốn dùng hàng free, dễ install và config. Không cần quá nhiều tính năng nhưng đủ để đáp ứng những nhu cầu cơ bản (text, table, image, ….)

Giao diện demo của Tinymce như sau: tinymce :>.png

Đơn giản, không màu mè nhưng khá đầy đủ nhu cầu đủ để soạn thảo và thêm vài thao tác cơ bản đúng hem :>

Tại sao lại là Tinymce?

  • Docs hướng dẫn sử dụng của thư viện này vô cùng dễ hiểu. Bạn hoàn toàn có thể copy paste và run, thế là xong.

    https://www.tiny.cloud/my-account/integrate/#react

    image.png

    Thư viện hỗ trợ đa nền tảng: HTML, React, Vue, Angular,…. Step by step với 2 bước chính: Cài đặt và thêm code snippet vào project của bạn. Dị hoi

  • Về giá cả: Thư viện nào cũng có bản trả phí và bản premium, chi tiết như bên dưới. Tuy nhiên nếu bạn muốn hosting thư viện thì sẽ hoàn toàn free, chỉ mất công tải về và config eslint thui nha :>

    • Phiên bản miễn phí: Phiên bản này bao gồm nhiều tính năng cơ bản và một số plugin phổ biến, đủ cho việc tích hợp vào các dự án web đơn giản.
    • Phiên bản cao cấp cung cấp nhiều tính năng nâng cao như: quản lý file (file manager), tính năng cộng tác (collaboration), kiểm tra chính tả tự động, và các plugin mở rộng khác. Bạn sẽ có free-trial 14 ngày nếu muốn trải nghiệm thử bản nâng cao này.
  • Tính năng: Đầy đủ các công cụ chỉnh sửa văn bản: bold, italic, underline, tạo bảng, thêm hình ảnh, video, liên kết.

  • Khả năng tùy chỉnh cao: Có thể dễ dàng tùy chỉnh giao diện, thanh công cụ và thêm các plugin theo nhu cầu.

  • Hỗ trợ mạnh mẽ cho plugin: Có hàng loạt plugin có sẵn cho các tính năng nâng cao như: kiểm tra chính tả, soạn thảo mã, quản lý file, xử lý hình ảnh.. Dễ dàng tích hợp với các plugin bên ngoài

  • Hiệu suất cao

So sánh với các thư viện khác

Dưới đây là Bảng so sánh giữa TinyMCE, CKEditor, Quill và Draft.js

Tiêu chí TinyMCE CKEditor Quill Draft.js
Tính năng Đầy đủ, nhiều plugin tùy chọn Nhiều tính năng cao cấp Cơ bản, nhẹ Tập trung vào React
Tùy biến Dễ dàng với nhiều plugin Tùy chỉnh mạnh mẽ Đơn giản, dễ tích hợp Phải code nhiều
Hiệu suất Nặng hơn do nhiều tính năng Hiệu suất tốt Nhẹ, tải nhanh Nhẹ, tối ưu tốt
Hỗ trợ cộng tác Không hỗ trợ (bản trả phí thì có) Có hỗ trợ cộng tác Không hỗ trợ Không hỗ trợ
Giấy phép Miễn phí (có trả phí cao cấp) Miễn phí (có trả phí cao cấp) Miễn phí Miễn phí

Nhận xét chung”

  • TinyMCECKEditor: Nhiều tính năng, mạnh mẽ cho dự án lớn.
  • QuillDraft.js: Nhẹ, linh hoạt, thích hợp cho ứng dụng cần hiệu suất tốt.

Nếu dự án của bạn cần một trình chỉnh sửa văn bản phong phú và mở rộng, TinyMCE và CKEditor là lựa chọn tốt. Nếu bạn cần sự nhẹ nhàng và đơn giản, Quill hoặc Draft.js là những giải pháp lý tưởng.

Qua so sánh ta thấy TinyMCE và CKEditor lý tưởng hơn. Vậy chọn thư viện nào?

  • Chọn TinyMCE: Nếu bạn cần dễ dàng tùy chỉnh, tích hợp nhanh chóng và đang làm việc với các framework hiện đại như React, Vue hoặc Angular. TinyMCE có giao diện dễ sử dụng và có thể mở rộng với nhiều plugin.
  • Chọn CKEditor: Nếu bạn cần một trình chỉnh sửa hiệu suất cao, hỗ trợ cộng tác thời gian thực hoặc nếu bạn muốn có một trình soạn thảo nhẹ với khả năng kiểm soát cao về cấu trúc và các thành phần. CKEditor có thể tùy chỉnh tốt và linh hoạt với các nhu cầu khác nhau, đặc biệt phù hợp cho các dự án lớn.

TinyMCE là sự lựa chọn của tôi bởi sự dễ dàng tùy chỉnh, đơn giản và vẫn có đáp ứng được khá phong phú nhu cầu sử dụng.

Những vấn đề gặp phải khi cài đặt TinyMCE ở dự án thực tế.

Trường hợp 1: Bạn dùng bản online

Sample code:

<Editor
  initialValue="<p>This is the initial content of the editor</p>"
  init={{
    apiKey: 'YOUR_API_KEY_HERE',
    script_url: 'https://cdn.tiny.cloud/1/YOUR_API_KEY_HERE/tinymce/5/tinymce.min.js', // TinyMCE CDN
    height: 500,
    menubar: true,
    plugins: 'link image table',
    toolbar: 'undo redo | formatselect | bold italic | alignleft aligncenter alignright | bullist numlist outdent indent | link image table',
    content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }',
  }}
  onEditorChange={handleEditorChange}
/>

1. YOUR_API_KEY và script_url

  • apiKey: Đừng quên thay thế 'YOUR_API_KEY_HERE' bằng khóa API thực từ TinyMCE.

image.png

Lấy api key ở đâu? Vẫn là trên docs của thư viện nha (https://www.tiny.cloud/my-account/integrate/#react)

  • script_url: Đường dẫn 'https://cdn.tiny.cloud/1/YOUR_API_KEY_HERE/tinymce/5/tinymce.min.js' để link thư viện của bạn với dự án. Nhớ thay thế 'YOUR_API_KEY_HERE' ở đây nữa nhé. Nếu không khai báo ở đây, bạn có thể khai báo trong thẻ script trong index.html
  • Cấu hình pluginstoolbar:
plugins: 'link image table',
toolbar: 'undo redo | formatselect | bold italic | alignleft aligncenter alignright | bullist numlist outdent indent | link image table'

2. onEditorChange

onEditorChange={(content, editor) => {
        // Xử lý thay đổi nội dung editor
        console.log("Content was updated:", content);
    }}
  • onEditorChange: Hàm onEditorChange cần được định nghĩa để xử lý khi có thay đổi nội dung. Khi console log, output của bạn sẽ là thẻ HTML.

Trường hợp 2: Bạn tự hosting thư viện

1. Download và config Tinymce

image.png

  • Thử yarn start xem có bị lỗi Eslint hay không. Nếu có, hãy tự thêm tay vào các file js để disbled eslint nhé.

2. Custom các tính năng bạn muốn hiển thị ở TextEditor này

Sử dụng onEditorChange để bắt các sự kiện thay đổi. Dưới đây là full code của mình, sample này bao gồm các tính năng tô màu chữ đơn giản, và thêm import ảnh từ local + insert ảnh là 2 tính năng mà KH bên mình yêu cầu thêm.

```tsx
function TextEditor(props: any) {
  const [textEditorValue, setTextEditorValue] = React.useState(props.value);
  const editorRef = useRef(null);

  const onEditorChange = (content: any, editor: any) => {
    setTextEditorValue(content || `<p></p>`); 
    // set giá trị của text editor (hoặc set là <p></p> nếu không có giá trị  
    // -> Không bị hiển thị null)
    props.setFieldValue(props.name, editor.getContent() || `<p></p>`);
  };

  return (
    <FieldContainer>
      <div className="label font-weight-bold">
        {props.label}
        <sup>({props?.order})</sup>
      </div>
      <Editor
        onEditorChange={onEditorChange}
        // lưu ý config đường dẫn thư viện này theo đúng đường dẫn của bạn
        tinymceScriptSrc="%PUBLIC_URL%/tinymce/js/tinymce/tinymce.min.js" 
        onInit={(evt, editor) => (editorRef.current = editor)}
        value={textEditorValue || ""}
        init={{
          height: 500,
          menubar: true,
          licenseKey: "gpl", // dòng này để xóa watermark của tinymce
          plugins: [
            "anchor",
            "autolink",
            "charmap",
            "codesample",
            "emoticons",
            "image",
            "link",
            "lists",
            "media",
            "searchreplace",
            "table",
            "visualblocks",
            "wordcount",
          ],
          toolbar:
            "undo redo | formatselect | bold italic backcolor | " +
            "alignleft aligncenter alignright alignjustify | " +
            "bullist numlist outdent indent | removeformat | table | link image | code",
          image_title: true,
          automatic_uploads: true,
          file_picker_types: "image",
          // File picker callback để chèn ảnh từ máy tính
          file_picker_callback: function (cb, value, meta) {
            const input = document.createElement("input");
            input.setAttribute("type", "file");
            input.setAttribute("accept", "image/*");
            input.onchange = function () {
              const file = (this as any).files[0];
              const reader = new FileReader();
              reader.onload = function () {
                const id = "blobid" + new Date().getTime();
                const blobCache = editorRef.current.editorUpload.blobCache;
                const base64 = (reader.result as string).split(",")[1];
                const blobInfo = blobCache.create(id, file, base64);
                blobCache.add(blobInfo);
                cb(blobInfo.blobUri(), { title: file.name });
              };
              reader.readAsDataURL(file);
            };

            input.click();
          },
          // Cho phép chèn ảnh từ URL
          image_caption: true,
          content_style:
            "body { font-family:Helvetica,Arial,sans-serif; font-size:14px }",
          promotion: false,
        }}
      />
      {props.error && props.touched[props.name] && (
        <div className="error">{props.error}</div>
      )}
    </FieldContainer>
  );
}

```

Giao diện của hệ thống mình:

image.png

Hãy thử sử dụng thư viện TinyMCE nếu KH bạn yêu cầu 1 trình soạn thảo cơ bản, đơn giản, dễ sử dụng và freee nhé 😊.</div>

</div>


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.