美文网首页vue 组件Vue
vue 富文本图片上传处理

vue 富文本图片上传处理

作者: 生爱_存在 | 来源:发表于2021-10-13 16:33 被阅读0次

    此处以 vue-quill-editor 进行示范,其他富文本大体都差不多
    可以粘贴直接从文件夹里复制出来的图片,也可以粘贴截图;

    <template>
      <div>
        <quill-editor v-model="content" ref="myQuillEditor" :options="editorOption" @blur="onEditorBlur($event)" @focus="onEditorFocus($event)" @change="onEditorChange($event)" />
        <!-- 图片上传组件 -->
        <file-upload @change="imgChange" id="enclosureInput" ref="ossUpload" :folderName="'financial'" :isMultiple="true" style="display: none" />
      </div>
    </template>
    
    import { quillEditor, Quill } from "vue-quill-editor";
    import { container, ImageExtend, QuillWatch } from 'quill-image-extend-module'
    Quill.register('modules/ImageExtend', ImageExtend)
    
    export default {
      components: {
        quillEditor,
      },
      data () {
        return {
          content: '',
          editorOption: {
            placeholder: "请在这里输入",
            modules: {
              toolbar: {
                container: container,
                handlers: {
                  'image': function (value) {
                    if (value) {
                      // 绑定上传图片按钮  自带的图片上传,我没用过,应该问题不大
                     document.getElementById('enclosureInput').children[0].children[0].children[0].click()
                    } else {
                      this.quill.format('image', false)
                    }
                  }
                }
              }
            }
          },
          oldIndex: 0, // 记录光标位置
          imgArr: [], // 用来存放图片的 base64 字符串、图片上传后的 url 和 图片上传状态
          subDisabled: false, // 判断是否可以提交
        }
      },
      methods: {
        //组件的change事件 非重点,不做介绍
        imgChange (fileList) {
        },
        onEditorReady (editor) {
        },
        onEditorBlur () {
    
        },
        // 失去焦点事件
        onEditorFocus () { console.log('获得焦点'); }, // 获得焦点事件
        // 内容改变事件
        onEditorChange () {
          this.oldIndex = this.$refs.myQuillEditor.quill.selection.savedRange.index;
        },
        pasteListener () {
          // 清空数组,防止脏数据
          this.imgArr.length = 0;
          // 监听粘贴事件
          document.getElementsByClassName('quill-editor')[0].removeEventListener("paste", this.listenerFn);
          document.getElementsByClassName('quill-editor')[0].addEventListener('paste', this.listenerFn);
        },
        // 取消监听事件
        removeListener () { document.getElementsByClassName('quill-editor')[0].removeEventListener("paste", this.listenerFn) },
    
        listenerFn (e) {
          let quill = this.$refs.myQuillEditor.quill;
          // 获取光标初始位置
          this.oldIndex = quill.selection.savedRange.index;
          if (!(e.clipboardData && e.clipboardData.items)) return;
          e.clipboardData.items.forEach(async item => {
            // 字符串
            if (item.kind == 'string') item.getAsString(str => { console.log(str); })
            else if (item.kind == 'file') {
              // 获取文件
              let file = await item.getAsFile();
              // 对指定格式的图片进行操作
              if (/\.(jpg|jpeg|png|GIF|JPG|PNG)$/.test(file.name)) {
                this.translateBlobToBase64(file, async baseStr => {
    
                  // 判断,如果是直接粘贴的文件,光标不会移动,需要手动往里面塞
                  if (this.oldIndex == quill.selection.savedRange.index) {
                    quill.insertEmbed(this.oldIndex, 'image', baseStr);
                    // 光标 +1
                    quill.setSelection(this.oldIndex + 1);
                  }
    
                  // 将base64转换为文件后,不同的图片放到数组中,然后进行上传操作;
                  // 通过上面的塞值操作之后,没粘贴一张图片,富文本中都会有对应的 base64 字符串去,通过字符串切割成数组的方式,判断是否有粘贴相同的图片,相同的图片 base64 编码是一样的,这样只需要上传一次即可
                  if (this.content.indexOf(baseStr) == -1 || (((this.content.split(baseStr)).length - 1) == 1)) {
                    let imgObj = {
                      baseStr, // base64 字符串,用于匹配和替换
                      state: false, // 上传状态,用来判断图片是否上传成功
                      url: undefined, // 图片上传成功后的地址
                    }
                    this.subDisabled = true;
                    // 图片上传,此处前端直接传 阿里oss,不同需求单独处理
                    let rsp = await uploadOSS({ file }, this.$refs.ossUpload.Aliyun, 'img');
                    if (rsp) {
                      // 上传成功之后,更改状态,并放到 imgArr 数组中,再遍历该数组,判断是否所有图片上传状态;
                      let obj = this.$refs.ossUpload.transformObj(rsp);
                      imgObj.state = true;
                      imgObj.url = obj.url;
    
                      this.imgArr.push(imgObj);
                      this.subDisabled = false;
                      this.imgArr.forEach(item => {
                        if (!item.state) this.subDisabled = true;
                      })
                    }
                  }
                  // 重新获取光标位置
                  this.oldIndex = quill.selection.savedRange.index;
                })
              }
            }
          })
        },
        // 将base64 全部替换成 url 
        // 此方法在提交数据之前执行
        imgChaec () {
          if (this.imgArr.length > 0) this.imgArr.forEach(item => this.content = this.content.replaceAll(item.baseStr, item.url));
        },
      }
    }
    

    总结:

    1. 使用了发布订阅者的设计思想,每个图片单独处理,互不影响;
    2. 可以粘贴文件夹里复制的图片;
    3. 传给后端的图片时 url 连接,减小数据库字段长度;
    4. 粘贴图片的时候,如果是截取的图片,组件自己会将截取的图片的 base64 编码放到组件数据中,因为数据不好判断,也不好获取数据中的 base64 编码,所以也手动根据 file 对象重新生成了 base64 编码,后续可以优化;
    5. 图片上传失败没有做处理,后续有时间优化;

    相关文章

      网友评论

        本文标题:vue 富文本图片上传处理

        本文链接:https://www.haomeiwen.com/subject/hwfeoltx.html