// 2019-3-27 更新,最初发在这里只是记录一下 CKeditor5 的发布,当时的版本还是 1.0.0-alpha.1,截止今日,已经更新为 v12.0.0,之前的一些方法已经不太兼容,特更新如下,希望能帮助到大家。
CKeditor5 相比 CKeditor4 更轻量级,可以按需定制很灵活,CKeditor5 是彻头彻尾的重写,支持移动端、支持按需定制,灵活的插件机制等。CKeditor5 和 CKeditor4 是完全不兼容的,使用方式也有许多不同。
在我们的项目中,使用 CKeditor5 实现了文章发布、图片上传、图片拖拽上传、剪贴板粘贴上传、以及复制图文内容实现远程图片自动本地化。
首先安装 CKeditor5 和 axios 库(上传需要)
yarn add @ckeditor/ckeditor5-build-classic
yarn add axios
相关代码
// Editor.js
import ClassicEditor from '@ckeditor/ckeditor5-build-classic'
import '@ckeditor/ckeditor5-build-classic/build/translations/zh-cn.js'
import CatchRemoteImage from './CatchRemoteImage'
export default class Editor {
constructor(element, config) {
let defaultConfig = {
toolbar: ['heading', '|', 'bold', 'italic', 'blockQuote', 'bulletedList', 'numberedList', 'link', 'imageUpload', 'undo', 'redo'],
language: 'zh-cn',
ckfinder: {
uploadUrl: '/upload'
}
};
this.element = element;
this.config = Object.assign(defaultConfig, config)
}
static create(element, config) {
const editor = new this(element, config);
ClassicEditor
.create(editor.element, editor.config)
.then(editor => {
const doc = editor.model.document;
// 远程图片上传
// 参考 https://github.com/ckeditor/ckeditor5-image/blob/master/src/imageupload/imageuploadediting.js#L78
editor.model.document.on('change', () => {
const changes = doc.differ.getChanges();
for (const entry of changes) {
if (entry.type === 'insert' && entry.name === 'image') {
const item = entry.position.nodeAfter;
// Check if the image element still has upload id.
const uploadId = item.getAttribute('uploadId');
const uploadStatus = item.getAttribute('uploadStatus');
if (!uploadId && !uploadStatus) {
CatchRemoteImage(editor, item);
}
}
}
});
})
.catch(error => {
console.log(error)
})
}
};
图文混合内容粘贴后,图片本地化方法脚本:
// CatchRemoteImage.js
import axios from "axios";
export default function (editor, imageElement) {
const uploadingImage = 'https://www.cshome.com/build/images/uploading.gif';
const failImage = 'https://www.cshome.com/build/images/upload-fail.jpg';
const imageUrl = imageElement.getAttribute('src');
const localDomains = ['cshome.com'];
const model = editor.model;
// 检测是否需要上传
function test(url) {
if (url.indexOf(location.host) !== -1 || /(^\.)|(^\/)/.test(url)) {
return true;
}
if (localDomains) {
for (let domain in localDomains) {
if (localDomains.hasOwnProperty(domain) && url.indexOf(localDomains[domain]) !== -1) {
return true;
}
}
}
return false;
}
// 图片上传
function upload(url) {
let data = new FormData();
data.append('url', url);
return axios.post(
'/upload-by-url',
data,
{
headers: {
'content-type': 'multipart/form-data'
}
})
}
if (/^https?:/i.test(imageUrl) && !test(imageUrl)) {
model.enqueueChange('transparent', writer => {
writer.setAttribute('src', uploadingImage, imageElement);
writer.setAttribute('uploadStatus', 'uploading', imageElement);
});
upload(imageUrl)
.then(response => {
model.enqueueChange('transparent', writer => {
writer.setAttribute('src', response.data.url, imageElement);
writer.setAttribute