CKEditor is introduced

CKEditor is a comprehensive rich text editor that has been around for many years. It supports all aspects of the editor well (vue, React, Angular are packaged). Today, I will summarize my experience in using CKEditor. This article summarizes the use of CKEditor5 in VUE, including classic, inline, ballon, and Document Editor.

Related links

  • Home address: ckeditor.com/
  • Github address: github.com/ckeditor
  • Document address: ckeditor.com/docs/index….

Method of use

CKEditor encapsulates Vue out of the box, but it certainly has some reduced functionality. See the documentation for details and use it in the same way as other plugins. Here is a description of the native use method.

Classic (Inline/Ballon/Ballon block) Editor

The Document Editor is slightly special and will be explained separately

  • The installation
npm install @ckeditor/ckeditor5-build-classic --save
npm install @ckeditor/ckeditor5-build-inline --save
npm install @ckeditor/ckeditor5-build-ballon --save
npm install @ckeditor/ckeditor5-build-ballon-block --save
Copy the code
  • create
// Take Classic Editor as an example. Other types of editors use the same method, <template> <div class="classic-editor"> <div id="editor-classic" /> </div> </template> <script lang='ts'> import { Component, Vue } from "vue-property-decorator"; import ClassicEditor from "@ckeditor/ckeditor5-build-classic"; import "@ckeditor/ckeditor5-build-classic/build/translations/zh-cn"; Export Default Class extends Vue {private editorDataCopy = ""; Private Editor: any = null; Private editorConfig = {language: / / public initEditor() {ClassicEditor. Create ()} / / public initEditor() {ClassicEditor. document.getElementById("editor-classic"), this.editorConfig ) .then((editor: any) => { this.editor = editor; Editor.setdata (this.editorDatacopy); // Initialize the contents of the editor. }) .catch((error: any) => { console.error("There was a problem initializing the editor.", error); }); } // Destroy editor beforeDestroy() {if(this.editor) {this.editor.destroy(); } } } </script> <style lang="scss"> .classic-editor { .ck-editor__editable { height: 300px; border: 1px solid #ddd ! important; box-shadow: none ! important; } } </style>Copy the code

Document Editor

  • The installation
npm install @ckeditor/ckeditor5-build-decoupled-document --save
Copy the code
  • create
<template> <div style="height: 100%"> <div id="toolbar-container" class="toolbar-container" /> <div id="editable-container" class="editable-container" /> </div> </template> <script lang='ts'> import DecoupledEditor from "@ckeditor/ckeditor5-build-decoupled-document"; import "@ckeditor/ckeditor5-build-decoupled-document/build/translations/zh-cn"; // The code above is the same, do not repeat, () {(this. EditorDataCopy, ()) {(this. EditorDataCopy,); this.editorConfig) .then((editor: Any) => {this.editor = editor // Document Editor needs to add a separate toolbar const toolbarContainer = document.getElementById("toolbar-container"); if (toolbarContainer) { toolbarContainer.appendChild(editor.ui.view.toolbar.element); } }) .catch((error: any) => { console.error("There was a problem initializing the editor.", error); }); } </script> <style lang=" SCSS "> // This is the default style of the official demo. Editable container {position: relative; border: 1px solid #ddd; border-top: 0; background: #eee; padding: 3em; overflow-y: scroll; height: calc(100% - 40px); .ck-editor__editable { width: 21cm; max-width: 100%; Min - height: 29.7 cm; margin: 0 auto; Padding: 1 cm 1.2 cm; border: 1px #d3d3d3 solid ! important; background-color: #fff; Box-shadow: 0 0 5px Rgba (0, 0, 0, 0.1)! important; } } </style>Copy the code

Custom image Upload Adapter

CKEditor5 supports custom image upload adaptors, mainly defining the method of uploading images, passing parameters and returning parameters, etc. If the upload method is relatively Simple, you can also consider using the officially defined plug-ins: Easy Image, Simple Adapter, Base64 Adapter. The following describes how to customize plug-in uploading.

Image upload process

  • Place images into an editor (paste from clipboard, drag and drop, or upload from system folder)
  • These images are intercepted by the Image Upload plug-in, which creates an instance of a File Loader for each uploaded image
    • A file loader reads a file from a disk and uploads it to the server through an Upload Adapter
    • The Upload Adapter submits an HTTP request to upload the image to the server and returns the corresponding URL
  • During the image upload process, the Image Upload plug-in does the following:
    • Create a placeholder for the image
    • Insert it into the editor
    • Display the progress bar for uploading pictures
    • Abort file uploads when images are deleted
  • When the image is successfully uploaded, the Upload Adapter parses the value returned by the Promise object and sets the corresponding URL to the image SRC

Upload adapter definitions

XMLHttpRequest is used in the official documentation. Since axios is used in the company’s project, the usage of AXIos is described here. If it does not meet your requirements, refer to the official documentation

class ImgUploadAdapter {
	private loader: any;

	constructor(loader: any) {
		this.loader = loader
	}

	PostFile is a file upload request function wrapped in AXIos. The request parameters and return parameter types are related to the interface implementation. You can define them based on the interface documentation. Because the interface in this article returns a relative path, you need to add the corresponding header URL
	upload() {
		return new Promise((resolve, reject) = > {
			const data = new FormData()
			this.loader.file.then((file: any) = > {
				data.append('file', file)
				postFile(FileTypeEnum.image, data).then((response: IResponseData<{ url: string }>) = > {
					resolve({
						default: `${process.env.VUE_APP_BASE_API}/api/v1/auth/file/get/image? url=${response.data.url}`
					})
				}).catch(error= > {
					reject(error)
				})
			})
		})
	}

	// The method to abort the file upload can be implemented by itself (axios has a method to cancel the request, because axios has a layer of encapsulation in the code, I won't post the detailed code here)
	abort() {}
}
Copy the code

Other configuration

Here you can simply use CKEditor5, only a small part of the content is introduced here, other basic configuration can refer to the official documentation, quite detailed (disadvantages are all In English, take your time to read, haha)

Q&A

ckeditor-duplicated-modules: Some CKEditor 5 modules are duplicated

The following error occurs when multiple types of editors are used at the same time. According to the official documentation, do not use two compiled editors at the same time because of various conflicts:

  • Cause of conflict

    • The code is so repetitive that editors of different compilations can share more than 99% of the code and load it twice or more, making the page cumbersome
    • Some repetitive CSS styles can cause problems with the editor’s display
    • Duplicate translation code contained in the compiled version code may result in inaccurate translation results
  • The solution

    There are two solutions, one is to build in WebPack Config and the other is to rebuild the CKEditor5 code. This article focuses on the latter method, and the main steps are as follows:

    • Clone the official code (ckeditor5-build-classic as an example)
    git clone -b stable https://github.com/ckeditor/ckeditor5-build-classic.git
    cd ckeditor5-build-classic
    npm install
    Copy the code
    • Install other versions of the editor (inline/ballon/document will be included here). Note that this is not the built version
    npm install --save-dev @ckeditor/ckeditor5-editor-inline @ckeditor/ckeditor5-editor-ballon @ckeditor/ckeditor5-editor-decoupled
    Copy the code
    • Rewrite the webpack entry file SRC /ckeditor.js
    // The editor to use
    import ClassicEditorBase from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
    import InlineEditorBase from '@ckeditor/ckeditor5-editor-inline/src/inlineeditor';
    import DecoupledEditorBase from '@ckeditor/ckeditor5-editor-decoupled/src/decouplededitor';
    import BalloonEditorBase from '@ckeditor/ckeditor5-editor-balloon/src/ballooneditor';
    
    class ClassicEditor extends ClassicEditorBase {}class InlineEditor extends InlineEditorBase {}class DecoupledEditor extends DecoupledEditorBase {}class BalloonEditor extends BalloonEditorBase {}// The plug-in is initially loaded
    constplugins = [...]  ClassicEditor.builtinPlugins = plugins InlineEditor.builtinPlugins = plugins DecoupledEditor.builtinPlugins = plugins BalloonEditor.builtinPlugins = plugins// Initial configuration
    constconfig = {... } ClassicEditor.defaultConfig = config; InlineEditor.defaultConfig = config; DecoupledEditor.defaultConfig = config; BalloonEditor.defaultConfig = config;export default {
        ClassicEditor, InlineEditor, DecoupledEditor, BalloonEditor
    }
    Copy the code
    • Redefine global variable names in Webpack
    // webpack.config.js
    output: {
    // library: 'ClassicEditor'
    library: 'CKEditor'
    }
    Copy the code
    • recompile
    // After the SRC /ckeditor.js and webpack.config.js changes are made, NPM build needs to be executed, and NPM run build needs to be recompiledCopy the code
    • Use the test
    // Once you're done, you can test <! Under samples/index.html. DOCTYPE html> <html lang="en">
    
    <head>
    <meta charset="utf-8"> <title>CKEditor 5 -- super build</title> <style> body {max-width: 800px; margin: 20px auto; } </style> </head> <body> <h1>CKEditor 5 -- super build</h1> <div id="classic-editor">
        <h2>classic editor</h2>
        <p>This is an instance of the <a href="https://ckeditor.com/docs/ckeditor5/latest/builds/guides/overview.html#classic-editor">classic editor build</a>.</p>
    </div>
    
    <div id="inline-editor">
        <h2>inline editor</h2>
        <p>This is an instance of the <a href="https://ckeditor.com/docs/ckeditor5/latest/builds/guides/overview.html#inline-editor">inline editor build</a>.</p>
    </div>
    
    <div id="document-editor">
        <h2>document editor</h2>
        <p>This is an instance of the <a href="https://ckeditor.com/docs/ckeditor5/latest/builds/guides/overview.html#document-editor">document editor build</a>.</p>
    </div>
    
    <div id="balloon-editor">
        <h2>balloon editor</h2>
        <p>This is an instance of the <a href="https://ckeditor.com/docs/ckeditor5/latest/builds/guides/overview.html#balloon-editor">balloon editor build</a>.</p>
    </div>
    
    <script src=".. /build/ckeditor.js"></script>
    <script>
    CKEditor.ClassicEditor
        .create(document.querySelector('#classic-editor'))
        .catch(err => {
            console.error(err.stack);
        });
    
    CKEditor.InlineEditor
        .create(document.querySelector('#inline-editor'))
        .catch(err => {
            console.error(err.stack);
        });
    
    CKEditor.DecoupledEditor
        .create(document.querySelector('#document-editor'))
        .catch(err => {
            console.error(err.stack);
        });
    
    CKEditor.BalloonEditor
        .create(document.querySelector('#balloon-editor'))
        .catch(err => {
            console.error(err.stack);
        });
    </script>
    </body>
    </html>
    Copy the code
    • How to use it after compiling
      • Publish to the NPM repository
      • Import compiled JS files directly into script

    If you’re not using more than one editor at a time, it’s probably a version problem. Update all CKEditor versions to the latest, then delete package-lock.json and node_modules, and retry ‘NPM install’