1,开始实现逻辑前,优先启项目,然后将ckeditor引入,大概如下:

1,npm i @ckeditor/ckeditor5-vue2
2,下载sdk,https://ckeditor.com/ckeditor-5/online-builder/#,打开这个地址,配完就可以下载
3,启动sdk,运行npm install ,npm run build,在build文件夹下就有一个ckeditor.js
在这里插入图片描述
直接将这个js放到我们的项目public下,通过script引入即可

接下来就是项目配置

1,配置图片上传,其实就是imageUpload这个插件,首先在组件ckeditor添加属性config
在这里插入图片描述2,配置菜单
在这里插入图片描述
3,在初始化方法中调用上传api
在这里插入图片描述
在这里插入图片描述
4,创建MyUploadAdapter类

import axios from 'axios'
export default class MyUploadAdapter {
  constructor(loader, url, token) {
    // 文件
    this.loader = loader;
    // 链接
    this.url = url;
    // token
    this.token = token;
  }

  // 特定方法,必须得有
  async upload() {
     return  this.uploadFile(this.loader.file);
  }

  //上传文件
  async uploadFile(file, resolve, reject) {
    const data = new FormData();
    data.append("file", file);
    let res = await axios({
      url: this.url,
      method: "POST",
      headers: {
        Host: this.url,
        "Content-Type": "multipart/form-data",
      },
      data: {
        fileBinaryData: data,
        upload_token: this.token,
        fileName: file.name,
      },
    })
    // console.log(res.data.tableListData[0].classIntroduce)
    return {
        // default: res.data.tableListData[0].classIntroduce,
        // 返回请求的图片路径
        default: res.data.url
      };

  }

  // 取消请求
  abort() {
    server.abortUpload();
  }

}

 

5,在我们的组件中引入即可,这样上传图片就完成了,整体代码

<template>
  <div>
    <ckeditor :editor="editor" :value="editorData" :disabled="disabled" :config="editorConfig" @ready="onEditorReady" @focus="onEditorFocus" @blur="onEditorBlur" @input="onEditorInput" @destroy="onEditorDestroy"></ckeditor>
  </div>
</template>

<script>
import MyUploadAdapter from './MyUploadAdapter.js'
export default {
  name: 'app',
  props: {
    editorData: {           // 初始默认值
      type: String,
      default: '',
    },
    disabled: {             // 是否只读
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      editor: ClassicEditor,
      // 七牛云的地址
      // url: '',
      // 本地mock数据接口
      url:'',
      // token
      token: '',
      editorConfig: {
        toolbar: [
          'heading',     // 标题
          '|',
          'fontfamily',  // 字体
          'fontsize',    // 字号
          'fontColor',   // 字体颜色
          'fontBackgroundColor',  // 背景颜色
          '|',
          'bold',        // 加粗
          'italic',      // 斜体
          'underline',   // 下划线
          'strikethrough',       // 删除线
          '|',
          'alignment:left',      // 左对齐
          'alignment:right',     // 右对齐
          'alignment:center',    // 居中对齐
          'alignment:justify',   // 分散对齐
          '|',
          'numberedList', // 数字编号
          'bulletedList', // 项目符号
          '|',
          'outdent',      // 左缩进
          'indent',       // 右缩进
          '|',
          'link',         // 链接
          'blockquote',   // 引用
          'insertTable',  // 插入表格
          'imageUpload',  // 插入图片
          'MediaEmbed',   // 视频插入
          'html5video',
          '|',
          'undo',         // 撤销
          'redo',         // 重做
        ],
        
      }
    };
  },
  methods: {
    // 初始化
    onEditorReady(editor) {
      console.log('初始化')
      // 上传图片的逻辑
      editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
        return new MyUploadAdapter(loader, this.url, this.token)
      }

    },
    // 聚焦
    onEditorFocus() {
      console.log('聚焦')
    },
    // 失去焦点
    onEditorBlur() {
      console.log('失去焦点')
    },
    // 输入
    onEditorInput() {
      console.log('输入')
    },
    // 页面卸载
    onEditorDestroy() {
      console.log('卸载')
    }
  },
}
</script>

<style >
.ck-rounded-corners .ck.ck-editor__main>.ck-editor__editable, .ck.ck-editor__main>.ck-editor__editable.ck-rounded-corners  {
  height: 200px !important;
}
</style>

更新完整版,具体可根据自己需求进行删减

<template>
  <div>
    <div style="border: 1px solid #ccc;">
      <Toolbar v-if="isToolbar" style="border-bottom: 1px solid #ccc" :editor="editor" :defaultConfig="toolbarConfig" />
      <Editor id="editor" v-model="model" v-resize="onResize" :style="{height:height}" @onFocus="onFocus" @onChange="onChange" :defaultConfig="editorConfig" @onCreated="onCreated" />
    </div>
  </div>
</template>
     
<script>
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'

export default {
  components: { Editor, Toolbar },
  name: 'wangeditor_',
  props: {
    height: {           // 高度
      type: String,
      default: '300px'
    },

    row: {              // 表单数据
      type: Object,
      default: () => { }
    },

    col: {              // 列属性
      type: Object,
      default: () => { }
    },

    value: {            // 内容
      type: String,
      default: ''
    },

    isToolbar: {        // 是否显示工具栏
      type: Boolean,
      default: true
    },

    read: {             // 是否只读
      type: Boolean,
      default: false
    },

    autoFocus: {        // 是否默认聚焦
      type: Boolean,
      default: false
    },

    scroll: {           // 是否支持滚动
      type: Boolean,
      default: true
    },

    maxLength: {        // 最大长度
      type: Number,
      default: 0
    },

    placeholder: {      // 默认提示
      type: String,
      default: '请输入内容...'
    },

    config: {           // 上传配置项
      type: Object,
      default: () => {
        //   useCdnDomain: true,              // 是否使用cdn加速域名
        //   disableStatisticsReport: false,  // 是否禁用日志报告
        //   uphost: [],                      //上传的host
        //   upprotocol: 'https',             // 上传域名协议
        //   region: null,                    // 选择上传域名区域
        //   retryCount: 3,                   // 上传自动重试次数
        //   concurrentRequestLimit: 3,       // 分片上传并发请求量
        //   checkByServer: false,            // 是否开启服务端文件签名校验
        //   checkByMD5: false,               // 是否开启MD5校验,在断点续传时,开启MD5校会将已上传的分片与当前分片进行MD5值对比,若不一致,则重传该分片,避免使用错误的分片,读取分片内容并计算md5会消耗一些时间,默认为false
        //   forceDirect: false,              // 是否上传全部采用直传方式
        //   chunkSize: 4,                    // 分片上传时每片的大小,默认为4,最大不超过1024,单位MB
        //   debugLogLevel: 'OFF',            // 允许程序在控制台输出日志
      }
    },

    putExtra: {         // 输入配置项
      type: Object,
      default: () => {
        //   fname: '',                       // 文件原始文件名
        //   customVars: {},                  // 自定义变量
        //   metadata: {},                    //防止自定义meta
        //   mimeType: '',                    // 所传的文件类型
      }
    },

    token: {            // token
      type: String,
      default: window.qiniuToken
    },

    url: {              // 上传地址
      type: String,
      default: 'url'
    }

  },
  data() {
    let w = this
    return {
      editor: null,       // 工具栏编辑器
      toolbarConfig: {    // 工具栏配置项
        // toolbarKeys: [    // 显示的菜单,默认全部

        // ],
        excludeKeys: [    // 隐藏的菜单
          // "bold",            // 粗体
          // "underline",       // 下划线
          // "italic",          // 斜体
          // "through",         // 删除线
          // "code",            // 行内代码
          // "sub",             // 下标
          // "sup",             // 上标
          // "clearStyle",      // 清除格式
          // "color",           // 字体颜色
          // "bgColor",         // 背景色
          // "fontSize",        // 字号
          // "fontFamily",      // 字体
          // "indent",          // 增加缩进
          // "delIndent",       // 减少缩进
          // "justifyLeft",     // 左对齐
          // "justifyRight",    // 右对齐
          // "justifyCenter",   // 居中对齐
          // "justifyJustify",  // 两端对齐
          // "lineHeight",      // 行高
          // "insertImage",     // 网络图片
          // "deleteImage",     // 删除图片
          // "editImage",       // 编辑图片
          // "viewImageLink",   // 查看链接
          // "imageWidth30",    // 图片宽度相对于编辑器宽度的百分比30
          // "imageWidth50",    // 图片宽度相对于编辑器宽度的百分比50
          // "imageWidth100",   // 图片宽度相对于编辑器宽度的百分比100
          // "divider",         // 分割线
          // "emotion",         // 表情
          // "insertLink",      // 插入链接
          // "editLink",        // 修改链接
          // "unLink",          // 取消链接
          // "viewLink",        // 查看链接
          // "codeBlock",       // 代码块
          // "blockquote",      // 引用
          // "headerSelect",    // 标题
          // "header1",         // 标题1
          // "header2",         // 标题2
          // "header3",         // 标题3
          // "header4",         // 标题4
          // "header5",         // 标题5
          // "todo",            // 待办
          // "redo",            // 重做
          // "undo",            // 撤销
          // "fullScreen",      // 全屏
          // "enter",           // 回车
          // "bulletedList",    // 无序列表
          // "numberedList",    // 有序列表
          // "insertTable",     // 插入表格
          // "deleteTable",     // 删除表格
          // "insertTableRow",  // 插入行
          // "deleteTableRow",  // 删除行
          // "insertTableCol",  // 插入列
          // "deleteTableCol",  // 删除列
          // "tableHeader",     // 表头
          // "tableFullWidth",  // 宽度自适应
          // "insertVideo",     // 插入网络视频
          // "uploadVideo",     // 上传视频
          // "editVideoSize",   // 修改视频尺寸
          // "uploadImage",     // 上传图片
          // "codeSelectLang",  // 选择语言
          // 'group-video',     // 上传视频工具
          // "group-image",     // 上传图片工具
          // "group-indent",    // 缩进
          // "group-justify",   // 对齐
          // "group-more-style" // 更多
        ]
      },
      percent: 0,         // 上传进度
      editorConfig: {     // 编辑器配置项
        placeholder: w.placeholder,       // 编辑器默认值
        readOnly: w.read,                 // 编辑器只读
        autoFocus: w.autoFocus,           // 编辑器自动聚焦
        scroll: w.scroll,                 // 编辑器是否可滚动
        maxLength: w.maxLength,           // 编辑器输入最大长度
        MENU_CONF: {                      // 菜单配置项
          uploadImage: {                  // 上传图片
            server: `url`,         						// 服务器地址
            fieldName: 'file',                          // 文件名称
            meta: {                                     // 配置参数
              token: window.qiniuToken,
            },

            customInsert(res, insertFn) {               // 上传成功回调
              insertFn(res.data.url)
            },
          },
          uploadVideo: {                   // 上传视频
            async customUpload(file, insertFn) {        // 自定义上传
              let url = await w.upload(file)
              insertFn(url)
            }
          }
        }
      },
      mode: 'default' // or 'simple'
    }
  },
  computed: {
        model: {
            get:function(){ //显示
                return this.value;
            },
            set:function(newValue){ //赋值
                this.$emit('input', newValue)
            }
        }
    },
  methods: {
    onResize(rect) {
      // 给底下元素加宽度百分百
      if (rect.width > 600) {
        this.$el.classList.add('restrictWidth');
        this.$el.classList.remove('noWidth');
      } else {
        this.$el.classList.add('noWidth');
        this.$el.classList.remove('restrictWidth');
      }
    },
    // 初始化
    onCreated(editor) {
      this.editor = Object.seal(editor) // 一定要用 Object.seal() ,否则会报错
      this.$nextTick(() => {
        // console.log(this.editor)
      })
    },

    onFocus() {

    },

    // 编辑器变化
    onChange(editor) {
      // console.log("onChange", editor.getHtml()); // onChange 时获取编辑器最新内容
      if (this.row) {

        // 使用正则表达式匹配img标签并添加style属性 设置宽度100%
        const regex = /<img([^>]*)>/g;
        let richText = editor.getHtml().replace(regex, '<img$1 style="white-space: pre-wrap; word-break: break-all; width: 100% ">')
        this.row[this.col.key] = richText
      }
      const demoElements = document.querySelectorAll('.w-e-image-container');
        demoElements.forEach(function(element) {
          element.style.width = '100%';
        });
    },

    // 获取编辑区的文本
    getContent() {
      const editor = this.editor;
      if (editor == null) return;
      // console.log(editor.getText()); // 执行 editor API
    },

    // 获取编辑区的html
    printEditorHtml() {
      const editor = this.editor;
      if (editor == null) return;
      return editor.getHtml()
    },

    // 替换编辑区的文本
    setContent(content) {
      const editor = this.editor;
      if (editor == null) return;
      editor.setHtml(content)
    },

    // 上传
    async upload(files) {
      this.files = files;
      let notification = this.$notify({
        message: '<span>正在上传' + this.percent + '%</span>',
        dangerouslyUseHTMLString: true,
        duration: 0
      });
      return new Promise((resolve, reject) => {
        // 集成分片上传sdk
        let observable = window.qiniu.upload(files, files.name, this.token, this.config, this.putExtra)
        observable.subscribe({
          next: (result) => {
            // 主要用来展示进度
            if (notification) {
              notification.message = '<i class="el-icon-loading"></i><span>正在上传' + Math.floor(result.total.percent) + '%</span>'
            }
          },
          error: (errResult) => {
            if(errResult.error && errResult.error == 'bad auth'){
              notification.close()
              this.$store.dispatch('getQiniuToken')
              this.upload(this.files)
            }else {
              notification.close()
              this.$notify({
                type: 'error',
                message: '上传失败',
              });
            }
          },
          complete: (result) => {
            // 接收成功后返回的信息
            notification.close()
            resolve(result.data.url)

          }

        })
      })

    },
  },

  mounted() {
    this.$store.dispatch('getQiniuToken').then(()=>{
      this.onCreated()
    })
  },

  beforeDestroy() {
    const editor = this.editor
    if (editor == null) return
    editor.destroy() // 组件销毁时,及时销毁编辑器
  }
}

</script>
<style src="@wangeditor/editor/dist/css/style.css"></style>
<style >
.restrictWidth .w-e-text-container {
  width: 40.4rem;
  min-height: 100px;
  margin: auto;
  padding-bottom: 0.5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
}
.noWidth .w-e-text-container {
  width: 100%;
  /* min-height: 30px; */
  margin: auto;
  padding-bottom: 0.5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
}

/* 将图片百分比大小控制去除 */
.w-e-bar > .w-e-bar-item:first-child,
.w-e-bar > .w-e-bar-item:nth-child(2),
.w-e-bar > .w-e-bar-item:nth-child(3) {
  display: none;
}

.w-e-toolbar > .w-e-bar-item:first-child,
.w-e-toolbar > .w-e-bar-item:nth-child(2),
.w-e-toolbar > .w-e-bar-item:nth-child(3) {
  display: block;
}

/* 取消图片可变化大小 */
.w-e-image-dragger {
  display: none;
}

/* 视频宽度100%,并消除间隙 */
.w-e-textarea-video-container > video {
  width: 100%;
  vertical-align: top;
}

/* 去除内边距 */
.w-e-textarea-video-container {
  padding: 0;
}

/* 去除图片自带底部间隙4px */
.w-e-selected-image-container > img {
  vertical-align: top;
}

/* 多个富文本组件同时存在时,让当前富文本最大化时保持在最顶层 */
.w-e-full-screen-container {
  z-index: 9999999999;
}
.w-e-full-screen-container #editor {
  background-color: #fff;
}
</style>
GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891 Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐