富文本编辑器:ckeditor(使用ckeditor4-vue)

最近,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: truepasteFilter: 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:
自带的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

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值