Sivo 悉见

Vue3中ckeditor5增加上传图片功能

匿名 · 更新于 2022/7/3

首先需要在Vue3中安装ckeditor5,参考vue3安装在线构建ckeditor5教程

继续接着以上教程,在vue代码中增加一个上传适配器,具体代码如下

<script lang="ts">
class MyUploadAdapter {
  loader: any;
  reader: any;
  // According to the document we need a constructor first
  constructor( loader: any ) {
    this.loader = loader;
  }

  upload() {     return new Promise( ( resolve, reject ) => {       // 使用 FileReader() 物件读取档案       const reader = this.reader = new window.FileReader();       // 触发 load 事件后,resolve 丟回物件完成 Promise       reader.addEventListener( 'load', () => {         //上传到服务器 使用以下代码 //this.loader.file.then( (file: Blob) => {       //   //此处忽略请求服务器接口代码   //   //接口上传图片成功后返回图片地址后使用以下代码将图片url地址返回       // resolve( { default: url } ); //});          //上传base64使用以下代码 resolve( { default: reader.result } );       } );

      // 触发错误事件,以 reject 丟回 Promise 实惠原因       reader.addEventListener( 'error', err => {         reject( err );       } );       // 触发 abort 事件时,以 reject() ,使 Promise 失败       reader.addEventListener( 'abort', () => {         reject();       } );

      // 告訴 FileReader 物件用 url 格式读取,用于设定 img.src 性质       this.loader.file.then( (file: Blob) => {         reader.readAsDataURL( file );       } );     } );   }

  // start abort()   abort() {     //  触发 FileReader abort 事件     this.reader.abort();   }

}

function MyAdapterPlugin(editor: any) {   editor.plugins.get( 'FileRepository' ).createUploadAdapter = ( loader: any ) => { return new MyUploadAdapter( loader ) }; } </script>


然后将插件加入到ckeditor配置中, 配置如下
editorConfig: {
    // The configuration of the editor.
    extraPlugins: [ MyAdapterPlugin ]
}
配置完成后,使用ckeditor 的uploadImage(上传图片)或imageInsert(上传/插入图片)插件即可完成图片base64上传,完整代码如下 
<template>
  <div style="width:1000px">
    <ckeditor :editor="state.editor" v-model="state.editorData" :config="state.editorConfig"></ckeditor>
  </div>
</template>
<script lang="ts">
class MyUploadAdapter {
  loader: any;
  reader: any;
  // According to the document we need a constructor first
  constructor( loader: any ) {
    this.loader = loader;
  }

  upload() {
    return new Promise( ( resolve, reject ) => {
      // 使用 FileReader() 物件读取档案
      const reader = this.reader = new window.FileReader();
      // 触发 load 事件后,resolve 丟回物件完成 Promise
      reader.addEventListener( 'load', () => {
        resolve( { default: reader.result } );
      } );

      // 触发错误事件,以 reject 丟回 Promise 实惠原因
      reader.addEventListener( 'error', err => {
        reject( err );
      } );
      // 触发 abort 事件时,以 reject() ,使 Promise 失败
      reader.addEventListener( 'abort', () => {
        reject();
      } );

      // 告訴 FileReader 物件用 url 格式读取,用于设定 img.src 性质
      this.loader.file.then( (file: Blob) => {
        reader.readAsDataURL( file );
      } );
    } );
  }

  // start abort()
  abort() {
    //  触发 FileReader abort 事件
    this.reader.abort();
  }

}

function MyAdapterPlugin(editor: any) {
  editor.plugins.get( 'FileRepository' ).createUploadAdapter = ( loader: any ) => { return new MyUploadAdapter( loader ) };
}
</script>
<script lang="ts" setup>
import {nextTick, onMounted, reactive} from "vue";

// @ts-ignore
import {Editor as ClassicEditor} from 'ckeditor5-custom-build/build/ckeditor';

const state = reactive({
  editor: ClassicEditor,
  editorData: '这是初始化内容',
  editorConfig: {
    // The configuration of the editor.
    extraPlugins: [ MyAdapterPlugin ],
    toolbar: {
      items: [
        'undo', 'redo',
        '|',
        'heading', //标题
        '|',
        'findAndReplace', 'selectAll',
        '|',
        'removeFormat', 'bold', 'italic', 'strikethrough', 'underline', 'code',
        //'subscript',  //下标
        //'superscript', //上标
        '|',
        //'specialCharacters', //特殊字符
        'horizontalLine', 'pageBreak',
        'codeBlock',  //插入代码块
        '|',
        '-',
        //'highlight', //高亮
        'fontSize', 'fontFamily', 'fontColor', 'fontBackgroundColor',
        '|',
        'link', //链接
        'blockQuote', 'insertTable',
        // 'uploadImage', //上传图片
        'imageInsert', //上传/插入图片
        // 'htmlEmbed',  //html片段
        '|',
        'bulletedList', 'numberedList', 'todoList',
        '|',
        // 'outdent',  //减少缩进
        //'indent',  //增加缩进
        'alignment',
        // '|',
        // 'textPartLanguage',  //语言选择
        '|',
        'sourceEditing'
      ],
      shouldNotGroupWhenFull: true
    },
    //link链接规则调整
    link: {
      decorators: {
        // toggleDownloadable: {
        //   mode: 'manual',
        //   label: 'Downloadable',
        //   attributes: {
        //     download: 'file'
        //   }
        // },
        openInNewTab: {
          mode: 'manual',
          label: 'Open in a new tab',
          defaultValue: true,    // This option will be selected by default.
          attributes: {
            target: '_blank',
            rel: 'noopener noreferrer'
          }
        }
      }
    }
  }
})


</script>

补充: 最近有网友反馈,增加上传适配器并不需要单独再写一个<script> ,可以将以上代码第一块<script>代码和setup的代码进行合并,具体是否可行本人没有尝试,大家可以自行测试