最近,vue项目中使用了富文本编辑器,经过反复研究,选择了ckeditor,ckeditor分为4和5,我们选的4,网上中文的相关资料比较少,总结一下使用的经验。
官方网站:https://ckeditor.com/ckeditor-4/,里面有下载,文档等,Add-ons里面还有额外的plugin。
构建vue项目
首先使用vue create ckeditor_example_1
创建vue项目,因为我们的控件使用了element-ui,因此进入项目先下载一下控件npm install --save element-ui
。
使用ckeditor4-vue构建基本富文本编辑器
在vue项目中使用ckeditor4有两种方式,一种是自己去官网下载ckeditor的包,解压放在项目里面,另一个就是使用他们包装好的ckeditor4-vue包,这里,我们就使用了该包,使用命令npm install --save ckeditor4-vue
下载包。
然后,创建编辑器文件Editor.vue:
<template>
<div>
<ckeditor ref="editor" :config="config" v-model="editorData"
@namespaceloaded="onNamespaceLoaded" @ready="onEditorReady"></ckeditor>
</div>
</template>
<script>
export default {
name: 'Editor',
data () {
return {
editorData: ''
}
},
props: {
config: {
type: Object,
default: () => {}
},
ready: {
type: Function,
default: () => {}
}
},
methods: {
onNamespaceLoaded (CKEDITOR) {
console.log(CKEDITOR)
},
onEditorReady (editor) {
this.ready(editor)
}
}
}
</script>
<style scoped>
</style>
这样一个基本的ckeditor就构建好了,在想要使用的地方引用该文件即可<editor ref="editor"></editor>
。
分析一下<ckeditor ref="editor" :config="config" v-model="editorData" @namespaceloaded="onNamespaceLoaded" @ready="onEditorReady"></ckeditor>
这行代码,需要注意的是editorData是编辑器里面的文本内容;config是编辑器的配置文件,如果基础的编辑器可以满足你的要求的话,可以不配置config,使用该对象,你可以在一个项目中配置多个不同的editor;onNamespaceLoaded是处理全局变量CKEDITOR完成的事件,也就是说,这之后才可以使用window.CKEDITOR变量;onEditorReady处理编辑器对象构建完成的事件,也就是说,在此之后,当前的编辑器对象才可以使用,比如进行插入文本等操作。
上图是默认的编辑器的样式(背景色我自己改了),下面说一下它的额外功能。
额外功能
修改配置文件
config里面有很多配置项,我们可以直接修改CKEDITOR.config影响所有的editor,也可以给单独的editor配置config。
https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_config.html
下面我们说一下,基本的editor遇到的问题,以及如何通过配置config解决
1.从其他地方复制HTML页面,粘贴,只保留了文字
在配置文件里面添加 allowedContent: true
和pasteFilter: null
去除文本的过滤功能。
2.编辑器的高度太低,不符合预期
在配置文件里面添加height: 500
配置编辑器的高度
3.想要指定语言为英语
在配置文件里面添加language: 'en'
配置编辑器的语言
4.想要自定义编辑器的toolbar
在配置文件里面添加toolbar的配置项,内容格式如下:
toolbar: [
{
name: 'code',
items: ['Source']
},
{
name: 'basicstyles',
items: [ 'Styles', '-', 'Bold', 'Italic', 'Strike', 'Underline', 'TextColor', 'BGColor', 'Font', 'FontSize' ]
},
{
name: 'styles',
items: ['RemoveFormat']
},
{
name: 'insert',
items: [ 'Table', "SpecialChar", "HorizontalRule", 'CodeSnippet']
}
,
'/',
{
name: 'paragraph',
items: ['Format', 'NumberedList', 'BulletedList','-', 'Indent', 'Outdent', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight' ]
},
{
name: 'links',
items: ['Link', 'Unlink']
},
{
name: 'document',
items: ['Undo', 'Redo']
}
]
其中,{}里面是分组,’/'表示换行,items是具体的button,具体button的名字,可以自己去看源码找,反正我没有在文档里面找到介绍所有toolbar button的内容。
注意,我这里的配置使用了很多额外的plugin,如果你没有配置extraPlugins的话,直接使用可能会出错。这里使用的额外的plugin有colorbutton, colordialog, dialog, indentblock, indentlist, justify, font, codesnippet,这些plugin不需要自己定义,可以直接在extraPlugins里面配置就可以使用了。
自定义plugin
下面介绍一下,如果想要自己定义一个插件的话,应该怎么做。
ckeditor自己带的image插件,我觉得用起来太麻烦,所以自己定义了一个图片上传的插件。插件代码如下:
import img from '../../assets/img.png'
export default {
init () {
window.CKEDITOR.plugins.add('myImage', {
icons:"myImage",
init: function(editor){
editor.addCommand("myImage", {
exec: function( editor ) {
let file = document.createElement('input')
file.type = 'file'
file.accept = 'image/*'
file.addEventListener('change', () => {
const reader = new FileReader();
reader.readAsDataURL(file.files[0]);
reader.onload = () => {
editor.insertHtml(`<img src="${reader.result}"/>`)
};
reader.onerror = error => {
console.error(error)
};
})
file.click()
}
});
editor.ui.addButton('MyImage',{
label:'Insert Image',
icon: img,
command:'myImage'
});
}
})
}
}
插件的路径是/src/components/plugins/myImage.js,图标使用的assets里面的img.png(我直接扒的ckeditor的图标,然后自己剪裁的,和他的image图标一模一样)。window.CKEDITOR.plugins.add('myImage'
这行代码是添加插件的主代码,myImage是我的插件名;editor.addCommand
添加一个命令,点击button的时候执行它,执行的方法就是exec;editor.ui.addButton
添加我们自己的button,里面的command配置之前定义的command即可,点击button的时候就执行该命令。上面的代码做的就是,点击添加的imagebutton的时候,打开上传文件的dialog,然后你选一张图片,把它转成base64插入editor之中。你可以修改代码,选择将图片上传到你自己的服务器,然后,插入图片的url。
好吧,插件写好了,但是,还没有调用,我们应该在哪里调用呢?可以看到我们使用了window.CKEDITOR变量,所以需要该变量生成完成之后,再调用,推荐放到onNamespaceLoaded里面调用。
import myImage from './plugins/myImage'
export default {
name: 'Editor',
methods: {
onNamespaceLoaded (CKEDITOR) {
console.log(CKEDITOR)
myImage.init()
}
}
}
plugin注册好了,那么我们的toolbar里面直接就有了吗?并不是,你还需要配置config文件的extraPlugins,把注册的plugin加上,配置toolbar,把注册的button加上,至于toolbar的位置,你也可以写plugin定义的时候指定,具体可以自己看文档。
config : {
extraPlugins: 'myImage',
toolbar: [
{
name: 'insert',
items: [ 'MyImage', 'Table', "SpecialChar", "HorizontalRule", 'CodeSnippet']
}
]
}
至此,自定义的插件就好了。启动之后,发现,button的图片显示不出来,经过调查,vue小图片打包成base64,这样的话,ckeditor显示不出来,修改vue的配置文件
vue.config.js(没有的话,自己添加,这是新版的vue,旧版的话,可能是修改自己的webpack配置文件),取消小文件打包成base64的配置。
module.exports = {
// ......
devServer: {
disableHostCheck: true,
port: 59999
},
chainWebpack: config => {
config.module
.rule('images')
.use('url-loader')
.loader('url-loader')
.tap(options => Object.assign(options, { limit: 0 }))
},
configureWebpack: {
plugins: [
]
}
}
这只是一个简单的自定义插件,没有使用dialog,也没有使用panel。
ckeditor定义dialog的话,配置很麻烦,而且样式和我们的项目不一致,改样式也很麻烦。因此,我迂回了一下,使用了自己的dialog,下面简单介绍一下,怎么使用自己的dialog。
自带的table的dialog:
我自定义的插入div的dialog:
这是我的使用自己的dialog的插件的定义:
import d from '../../assets/div.png'
export default {
init () {
window.CKEDITOR.plugins.add('myDialog', {
icons:"myDialog",
init: function(editor){
editor.addCommand("myDialog", {
exec: function( editor ) {
console.log(editor)
editor.dialog.show()
}
});
editor.ui.addButton('MyDialog',{
label:'Show Dialog',
icon: d,
command:'myDialog'
});
}
})
}
}
我们定义了一个button,点击的时候执行代码editor.dialog.show()
,其中的dialog就是我们自定义的dialog,它有个方法叫show,就是显示dialog。那么,这个dialog究竟是在哪里加入editor这个对象的呢?editor对象是ckeditor的内置对象,并没有我们的dialog这个对象,还记得之前定义的时候的@ready="onEditorReady"
吗?是的,我们可以定义在onEditorReady方法里面。
onEditorReady (editor) {
editor.dialog = this.$refs.dialog
}
其中,this.$refs.dialog
就是我们自定义的dialog对象。至于dialog的具体定义,你可以自己创建一个dialog.vue文件,自定义。
监听editor的事件
onEditorReady (editor) {
//监听paste事件,处理copy/paste图片
editor.on( 'paste', async evt => {
if(evt.data.dataTransfer.getFilesCount() > 0) {
evt.data.dataValue = ''
let res = await this.handleTransferImage(evt)
if(res){
editor.insertHtml(`<img src="${res.url}"/>`)
}
}
})
//监听key的事件,实现tab的时候,调用indent命令
editor.on( 'key', function( event ) {
let keycode = event.data.keyCode;
if( keycode == 9 ) {
event.cancel();
editor.execCommand('indent')
}
})
},
其他的基础功能
//自定义ckeditor的背景色和字体颜色
onNamespaceLoaded (CKEDITOR) {
CKEDITOR.addCss(`body{background: #7b8b6f;color: white;}`)
},
//设置editor的html文本内容
setContent (data) {
this.editorData = data
//this.$refs.editor.instance.setData(data)
},
//获取editor的html文本内容
getContent () {
//return this.$refs.editor.instance.getData()
return this.editorData
},
//在鼠标处插入指定的html
insertHtml (html) {
this.$refs.editor.instance.insertHtml(html)
},
//执行editor内置的command
execCommand (command) {
this.$refs.editor.instance.execCommand(command)
},
//将editor设为readonly的
setReadonly (readonly) {
this.$refs.editor.instance.setReadOnly(readonly)
},
//判断是否是readonly的
isReadonly () {
return this.$refs.editor.instance.readOnly
},
//disable/enable指定的command
setDisable(command, disable) {
if(disable) {
this.$refs.editor.instance.commands[command].enable()
} else {
this.$refs.editor.instance.commands[command].disable()
}
},
//获取指定的command,比如'source'
getCommand (command) {
return this.$refs.editor.instance.commands[command]
}
遇到的问题
1.官网的Add-ons里面的插件不能直接使用,必须自己下载源码然后改写
2.使用的都是cdn的资源,公司网络问题,速度特别慢,初始化需要10s左右,难以接受
由于公司网络问题,没有办法使用ckeditor的cdn,最后,放弃了使用ckeditor4-vue,自己去官网下载了ckeditor的资源包,解压放到项目里面使用了,下次介绍一下,这种用法要怎么做。
代码仓库:https://github.com/gaograce/ckeditor-vue-example1.git