之前,直接使用的ckeditor-vue实现的富文本编辑器,问题主要是使用add-ons里面的plugin比较麻烦,需要自己包装,然后如果想要更改固有的plugin,比如table、tableselection比较麻烦。
于是,为了更方便使用修改plugin,我们采用了第二中方式,从官网下载解压package,直接放到项目里面。

下载

官网地址:https://ckeditor.com/ckeditor-4/download/
可以根据需要直接选择前三个下载,也可以定制自定义的,如果你想要使用额外的add-ons里面的plugin、或者想要未优化的源码方便修改的话,建议使用ONline Builder自定义下载包。而且,自定义的构建器还可以选择语言、皮肤什么的。
在这里插入图片描述
最后,同意协议,可以选择优化后的或者源码(如果你想要修改ckeditor的源码的话,选择源码,否则,选择optimized比较快),download即可。
在这里插入图片描述

使用

将下载包解压,放到vue的项目下的public目录下(该目录下的文件不打包,直接复制到结果里面),项目目录样式如下:
在这里插入图片描述
然后,在index.html文件里面引入ckeditor.js文件

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title><%= htmlWebpackPlugin.options.title %></title>
    <script src="<%= BASE_URL %>ckeditor/ckeditor.js"></script>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

创建CkEditor.vue文件,然后在App.vue里面引用即可使用。

<template>
  <div>
    <textarea :id='id'></textarea>
  </div>
</template>

<script>
  import MyDialog from './MyDialog'
  export default {
    name: 'CkEditor',
    mounted: function () {
      const self = this
      let CKEDITOR = window.CKEDITOR
      console.log(CKEDITOR)

      // 渲染编辑器
      let ckeditor = window.CKEDITOR.replace(self.id, {
        height: 500,
        language: 'en',
        allowedContent: true,
        pasteFilter: null,
        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']
          },
          '/',
          {
            name: 'paragraph',
            items: ['Format', 'NumberedList', 'BulletedList', '-', 'Indent', 'Outdent', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'lineheight']
          },
          {
            name: 'links',
            items: ['Link', 'Unlink', '-', 'Subscribe', 'Unsubscribe', 'HtmlTemplate']
          },
          {
            name: 'document',
            items: ['Undo', 'Redo']
          }
        ]
      })

      //处理图片copy、paste
      ckeditor.on('paste', async evt => {
        if (evt.data.dataTransfer.getFilesCount() > 0) {
          evt.data.dataValue = ''
          if (evt.data.dataTransfer.getFilesCount()) {
            let file = evt.data.dataTransfer.getFile(0)
            const reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = () => {
              self.ckeditor.insertHtml(`<img src="${reader.result}"/>`)
            };
            reader.onerror = error => {
              console.error(error)
            }
          }
        }
      })
      //处理tab
      ckeditor.on('key', function (event) {
        let keycode = event.data.keyCode
        if (keycode === 9) {
          event.cancel()
          ckeditor.execCommand('indent')
        }
      })

      ckeditor.on('instanceReady', () => {
        self.ckeditor = ckeditor
        console.log(ckeditor)
      })

      // 监听内容变更事件
      ckeditor.on('change', function () {
        self.$emit('contentChanged', self.ckeditor.getData())
      })
    },
    data: function () {
      return {
        id: parseInt(Math.random() * 10000).toString(),
        textarea: '',
        ckeditor: null
      }
    },
    methods: {
      insertDiv (data) {
        this.ckeditor.insertHtml(data)
      }
    }
  }
</script>

<style scoped>

</style>

注意上面的配置文件里面的height、allowedContent、toolbar都可以不配置,这里是为了获得自己想要的效果,自定义的配置。

自定义插件

下面,我们要定义一个插件mydialog,具体步骤如下。
首先,在public/ckeditor/plugins下面添加文件夹mydialog,该文件夹里面包含icons目录和plugin.js文件,如图所示:
在这里插入图片描述
icons里面是图标mydialog.png,plugin.js是插件定义,代码如下:

CKEDITOR.plugins.add('mydialog', {
  icons: 'mydialog',
  init: function (editor) {
    editor.addCommand('mydialog', {
      exec: function (editor) {
        editor.dialog.show()
      }
    })
    editor.ui.addButton('MyDialog', {
      label: 'Open My Dialog',
      command: 'mydialog'
    })
  }
})

其中,icons是图标,名字和icons下面的图片一致,然后,定义一个button和一个点击button时候执行的命令即可。
插件定义好了,那么要怎么使用它呢?
我们修改CkEditor.vue文件,使自定义插件生效:

<template>
  <div>
    <textarea :id='id'></textarea>
    <my-dialog ref="dialog" @content-changed="insertDiv"></my-dialog>
  </div>
</template>

<script>
  import MyDialog from './MyDialog'
  export default {
    name: 'CkEditor',
    mounted: function () {
      const self = this
      let CKEDITOR = window.CKEDITOR
      console.log(CKEDITOR)

      // 渲染编辑器
      let ckeditor = window.CKEDITOR.replace(self.id, {
        height: 500,
        language: 'en',
        //自定义插件(位于public下的ckeditor/plugins/mydialog)
        extraPlugins: 'mydialog',
        removePlugins: 'resize',
        allowedContent: true,
        pasteFilter: null,
        toolbar: [
          {
            name: 'code',
            items: ['Source']
          },
          {
            name: 'basicstyles',
            items: ['Styles', '-', 'Bold', 'Italic', 'Strike', 'Underline', 'TextColor', 'BGColor', 'Font', 'FontSize']
          },
          {
            name: 'styles',
            items: ['RemoveFormat']
          },
          {
            name: 'insert',
            items: ['MyDialog', 'Table', 'SpecialChar', 'HorizontalRule']
          },
          '/',
          {
            name: 'paragraph',
            items: ['Format', 'NumberedList', 'BulletedList', '-', 'Indent', 'Outdent', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight']
          },
          {
            name: 'links',
            items: ['Link', 'Unlink', '-', 'Subscribe', 'Unsubscribe', 'HtmlTemplate']
          },
          {
            name: 'document',
            items: ['Undo', 'Redo']
          }
        ]
      })

      ckeditor.on('paste', async evt => {
        if (evt.data.dataTransfer.getFilesCount() > 0) {
          evt.data.dataValue = ''
          if (evt.data.dataTransfer.getFilesCount()) {
            let file = evt.data.dataTransfer.getFile(0)
            const reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = () => {
              self.ckeditor.insertHtml(`<img src="${reader.result}"/>`)
            };
            reader.onerror = error => {
              console.error(error)
            }
          }
        }
      })
      ckeditor.on('key', function (event) {
        let keycode = event.data.keyCode
        if (keycode === 9) {
          event.cancel()
          ckeditor.execCommand('indent')
        }
      })

      ckeditor.on('instanceReady', () => {
        self.ckeditor = ckeditor
        ckeditor.dialog = self.$refs.dialog
        console.log(ckeditor)
      })

      // 监听内容变更事件
      ckeditor.on('change', function () {
        self.$emit('contentChanged', self.ckeditor.getData())
      })
    },
    data: function () {
      return {
        id: parseInt(Math.random() * 10000).toString(),
        textarea: '',
        ckeditor: null
      }
    },
    methods: {
      insertDiv (data) {
        this.ckeditor.insertHtml(data)
      }
    },
    components: {
      MyDialog
    }
  }
</script>

<style scoped>

</style>

主要修改内容:

  • 配置文件里面加extraPlugins: 'mydialog',,引入插件;
  • import插件界面文件MyDialog,把dialog界面引入;
  • toolbar配置里面加入'MyDialog'按钮
  • instanceReady里面加入ckeditor.dialog = self.$refs.dialog,把界面对象赋值给editor
  • 添加<my-dialog ref="dialog" @content-changed="insertDiv"></my-dialog>dialog界面
  • 添加insertDiv方法(插入div)

MyDialog文件内容如下:

<template>
  <el-dialog title="Insert A Div" :visible.sync="showDialog" width="50%">
    <el-form label-width="120px" label-position="left">
      <el-form-item label="color:" >
        <el-color-picker v-model="color"></el-color-picker>
      </el-form-item>
      <el-form-item label="background:">
        <el-color-picker v-model="background"></el-color-picker>
      </el-form-item>
      <el-form-item label="border">
        <el-input v-model="border" style="width: 300px"></el-input>
      </el-form-item>
    </el-form>
    <span slot="footer" class="dialog-footer">
    <el-button @click="showDialog = false">Cancel</el-button>
    <el-button type="primary" @click="save">OK</el-button>
  </span>
  </el-dialog>
</template>

<script>
  export default {
    name: 'MyDialog',
    data () {
      return {
        showDialog: false,
        color: '#000',
        background: '#fff',
        border: '1px solid #ccc'
      }
    },
    methods: {
      show () {
        this.showDialog = true
      },
      save () {
        let div = `<div style="color: ${this.color}; background: ${this.background}; border: ${this.border}; padding:5px 10px;">&nbsp;</div>`
        this.$emit('content-changed', div)
        this.showDialog = false
      }
    }
  }
</script>

<style scoped>

</style>

最后的实现效果:
点击自定义button,弹出如下对话框,点击ok,插入div。
在这里插入图片描述
插入的div如下所示:
在这里插入图片描述

这里我们的自定义插件的界面使用的是自己的界面,ckeditor提供了自己的dialog,如果要使用ckeditor的dialog,就不需要定义MyDialog文件了,可以直接在plugin.js里面定义界面,具体怎么做可以去官网查。

代码仓库:
https://github.com/gaograce/ckeditor-vue-example2.git

Logo

前往低代码交流专区

更多推荐