我们在使用该富文本框的时候,直接剪切图片到编辑区,默认是插入了 base64的图片格式,如果是单张图片还好,多张图片会导致数据库字段储存过长,在加载接口数据也很耗时,so。。。要么我们禁用粘贴复制图片的功能,给个友情提示,要么我们拦截图片上传到服务器拿到URL地址再插入到编辑区。

插件地址: https://quilljs.com/

vue初始化插件,提取重要部分,其他代码忽略。。。。

//html代码
<div class="editor" ref="editor" :style="styles" 
    @dragover.prevent="handleDragOver"
    @drop.prevent="handleDrop" 
    ></div>
    
//初始化
const editor = this.$refs.editor;
this.Quill = new Quill(editor, this.options);

第一种禁用粘贴复制图片

 data() {
    return {
      content: ``, // 富文本编辑器默认内容
      options: {
        //  富文本编辑器配置
        modules: {
          clipboard: {
              // 粘贴版,处理粘贴时候带图片
              matchers: [[Node.ELEMENT_NODE, this.handleCustomMatcher]],
            },
          //工具栏定义的
          toolbar: [
            ["bold", "italic", "underline", "strike"],       // 加粗 斜体 下划线 删除线
            ["blockquote", "code-block"],                    // 引用  代码块
            [{ list: "ordered" }, { list: "bullet" }],       // 有序、无序列表
            [{ indent: "-1" }, { indent: "+1" }],            // 缩进
            [{ size: ["small", false, "large", "huge"] }],   // 字体大小
            [{ header: [1, 2, 3, 4, 5, 6, false] }],         // 标题
            [{ color: [] }, { background: [] }],             // 字体颜色、字体背景颜色
            [{ align: [] }],                                 // 对齐方式
            ["clean"],                                       // 清除文本格式
            ["link", "image", "video"]                       // 链接、图片、视频
          ],
        },
        //主题
        theme: "snow",
        placeholder: "请输入正文"
      }
    };
  },

自定义的匹配器method 下

handleCustomMatcher (node, Delta) {
    let ops = []
    Delta.ops.forEach(op => {
        if (op.insert && typeof op.insert === 'string') {// 如果粘贴了图片,这里会是一个对象,所以可以这样处理
            ops.push({
                insert: op.insert,
            })
        } else {
            if (op.insert.image.includes('file://') || op.insert.image.includes('data:image/') ) {  //本地图片会使文件file开头 和 base64 开头data:image/
                this.$message.warning('不允许粘贴图片,请手动上传')
            } else {
                ops.push({
                    insert: op.insert,
                })
            }
        }
    })
    Delta.ops = ops
    return Delta
}

第二种获取到图片,然后上传到服务器,拿到URL再插入编辑器中

handleCustomMatcher (node, Delta) {
    let ops = []
    Delta.ops.forEach(op => {
        if (op.insert && typeof op.insert === 'string') {// 如果粘贴了图片,这里会是一个对象,所以可以这样处理
            ops.push({
                insert: op.insert,
            })
        } else {
            if (op.insert.image.includes('file://') || op.insert.image.includes('data:image/') ) {  //本地图片会使文件file开头 和 base64 开头data:image/

                //处理图片上传到服务器  
                //request是我的自定义函数,请替换成您的上传函数 Promise
                request({
                  url: '/common/uploadBase64',
                  method: 'post',
                  data: { file: op.insert.image }//base64 数据
                }).then(url => {
                  let length = this.Quill.getSelection().index; //光标位置
                  this.Quill.insertEmbed(length, "image", url ); // 插入图片  图片地址
                  this.Quill.setSelection(length + 1);
                }).catch(err => {
                  this.$message.error(err)
                })
            } else {
                ops.push({
                    insert: op.insert,
                })
            }
        }
    })
    Delta.ops = ops
    return Delta
}

ok 这里基本使用完成啦。。。。

其他功能:如果我们想直接拖动图片到编辑区中,然后上传呢?开头在初始化的时候定义了

@dragover.prevent="handleDragOver"
@drop.prevent="handleDrop" 

拖动函数,哈哈,我们监听这2个函数即可,代码如下:

// 处理拖拽事件目标元素
    handleDragOver(event) {
      //console.log(event);
    },
    //作用于目标元素
    handleDrop(event) {
      const files = event.dataTransfer.files;
      if (files.length > 0) {
        console.log(files);
        const formData = new FormData();
        formData.append("file", files[0]);
        //request是我的自定义函数,请替换成您的上传函数 Promise
        request({
          url: '/common/upload',
          method: "post",
          data: formData,
          headers: {
            "Content-Type": "multipart/form-data", 
           }
        }).then((res) => {
          if (res.code == 200) {
            let length = this.Quill.getSelection().index; //光标位置
            this.Quill.insertEmbed(length, "image", url ); // 插入图片  图片地址
            this.Quill.setSelection(length + 1);
          } else {
            this.$message.error("图片插入失败");
          }
        })
      }
    },

wow! 这样我们就完成了,该插件的改造了,其它的待续………

拖拽事件彩蛋1:

被拖动元素相关事件: 

事件描述
dragstart用户开始拖动元素时触发
drag元素正在拖动时触发
dragend用户完成元素拖动后触发

容器相关事件如下所示:

事件描述
dragenter当被鼠标拖动的对象进入目标容器时触发此事件
dragover当被拖动的对象在目标容器范围内拖动时触发此事件
dragleave当被鼠标拖动的对象离开目标容器时触发此事件
drop在一个拖动过程中,释放鼠标键到目标容器时触发此事件