在Vue中使用CKEditor5富文本编辑器

在项目中遇到富文本编辑器需要实现粘贴图片的功能,使用场景:如用户在其他地方截图可以直接在富文本编辑器内粘贴。

找了一圈市面上开源免费的富文本编辑器,最后选中CKEditor。ckeditor  document build 版本默认是可以粘贴图片的, 其他build版本没有尝试。

安装: 有好几种build版本可以选,我选用的是@ckeditor/ckeditor5-build-decoupled-document ,官方也有基于Vue框架的使用方法,尝试了一下一直报错,作罢。

npm install --save @ckeditor/ckeditor5-build-decoupled-document

使用:我是把ckeditor封装成一个业务组件,方便在各个页面中使用

ckeditor上传文件一般需要自己写一个文件适配器

//ckeditor 富文本编辑器自定义上传图片adapter

//文件上传到七牛云 后端提供上传接口
import { qiniuInfo, uploadFile } from '@/api/common';

export default class UploadImageAdapter {
  constructor(loader) {
      this.loader = loader
      this.imgURL = "xxxxxx" //这个是图片域名
  }

  async upload() {
    //获取到用户上传的文件
    const img = await this.loader.file;

    const promise = new Promise(async (resolve, reject) => {
      const { data, status } = await qiniuInfo();
      if (status !== 200) reject(false)
      const formData = new FormData();
      //token为上传到七牛云所需要的
      formData.append('token', data.token);
      formData.append('file', img);
      const res = await uploadFile(formData).catch(() => {});
      if (res.status === 200) {
        //必须要要以 default: imgurl形式
        let response = {
          default: `${this.imgURL}${res.data.hash}` //图片全链接
        }
        resolve(response)
      } else {
        reject(false)
      }
    })
    return promise
  }


  abort() {
    //可以书写删除服务器图片的逻辑
  }
}
<template>
  <div>
    <!-- 工具栏容器 -->
    <div id="toolbar-container"></div>
    <!-- 编辑器容器 -->
    <div id="editor"></div>
  </div>
</template>

<script>


import CKEditor from '@ckeditor/ckeditor5-build-decoupled-document';
//中文包
import '@ckeditor/ckeditor5-build-decoupled-document/build/translations/zh-cn';
//上传图片所需的适配器
import UploadImageAdapter from '@/jslibs/UploadImageAdapter';

export default {
  name: 'ckeditor',
  props: {
    value: {
      required: true,
    }
  },
  data() {
    return {
      editor: null,
    }
  },
  mounted(){
    this.initCKEditor()
  },
  methods:{
    initCKEditor() {
      CKEditor.create(document.querySelector('#editor'), 
        toolbar: [
          'heading',
          '|',
          'bold',
          'italic',
          'Underline',
          'fontSize',
          'numberedList',
          'bulletedList',
          'blockQuote',
          '|',
          'alignment:left',
          'alignment:right',
          'alignment:center',
          'alignment:justify',
          '|',
          'imageUpload',
          'Link',
          '|',
          'undo', //撤销
          'redo',//重做
        ],
        heading: {
          options: [
            { model: 'paragraph', title: '段落', class: 'ck-heading_paragraph' },
            { model: 'heading6', view: 'h6', title: '标题6', class: 'ck-heading_heading6' },
            { model: 'heading5', view: 'h5', title: '标题5', class: 'ck-heading_heading5' },
            { model: 'heading4', view: 'h4', title: '标题4', class: 'ck-heading_heading4' },
            { model: 'heading3', view: 'h3', title: '标题3', class: 'ck-heading_heading3' },
            { model: 'heading2', view: 'h2', title: '标题2', class: 'ck-heading_heading2' },
            { model: 'heading1', view: 'h1', title: '标题1', class: 'ck-heading_heading1' }
          ]
        },
        language: 'zh-cn'
        fontSize: {
          options: ['default',14, 16, 18, 20, 22, 24]
        }
      }).then(editor => {
        const toolbarContainer = document.querySelector('#toolbar-container');
        toolbarContainer.appendChild(editor.ui.view.toolbar.element);
        this.editor = editor //将编辑器保存起来,用来随时获取编辑器中的内容等,执行一些操作
        //使用图片上传适配器
        editor.plugins.get('FileRepository').createUploadAdapter = ( loader ) => {
            return new UploadImageAdapter(loader)
        };
        editor.model.document.on('change:data', () => {
          //把富文本编辑器获取到的内容传出去
          this.$emit('input', editor.getData())
        });
         //编辑的时候设置富文本编辑器的内容
        editor.setData(this.value);
      }).catch(error => {
        console.error(error);
      });
    },
  }
}
</script>

<style lang="less" scoped>

//设置编辑器内容区域最小高度
#editor {
  min-height: 380px;
  border: 1px solid #c4c4c4;
}
/deep/.ck-content {
  min-height: 380px;
}
</style>

图片上传成功后 我们也许会有在编辑器中拖拽改变图片大小的需求,ckeditor中也是比较方便的,自带ImageResize插件,该插件在@ckeditor/ckeditor5-image 下面,安装该插件使用即可。

踩坑1:当我们使用build版本时,可能已经安装了@ckeditor/ckeditor5-image 但是没有引入ImageResize,这时我们再安装就会报错 ckeditor-duplicated-modules: Some CKEditor 5 modules are duplicated.
如何解决呢? 我的解决办法是 从github上clone一份对应版本没有打包的源代码,修改配置,重新打包,替换项目依赖中的build文件夹

git clone https://github.com/ckeditor/ckeditor5-editor-decoupled.git

//clone完成后在项目目录src下的ckeditor.js文件中

import ImageResize from '@ckeditor/ckeditor5-image/src/imageresize';

//把ImageResize加到DecoupledEditor.builtinPlugins中
//npm run build

踩坑2: 由于我是模拟v-model的实现,在富文本内容发生变化的时候向外触发input事件并发送内容,富文本组件接受名为value的props,监听value值改变就调用setData方法,这会导致一个问题, 每次输入change都会被触发两次(一次是用户输入内容触发的,一次是value改变setData触发),不知到是不是这个原因,每次输入内容都会导致光标回到内容的开始位置。

解决方法:不在采用类似v-model方式,而是向外暴露两个方法 

//数据变化时把值保存到content字段
editor.model.document.on('change:data', () => {
    this.content = editor.getData();
 });

//向外暴露获取值和设置值的方法

getContent() {
  return this.content
}

setContent(val) {
  this.editor.setData(val)
}

//在使用页面
<ck-editor ref="editor"></ck-editor> 

//获取值
let content = this.$refs.editor.getContent()

//设置值
this.$refs.editor.setContent(data)

 

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值