vue-quill-editor的大图片上传问题解决

项目中有个使用vue-quill-editor富文本编辑器的功能,当上传大图片时,图片资源会被转成base64格式,当图片过大时字符串的大小可能达到2M以上,数据库无法保存。

vue-quill-editor提供了一个 handlers 可以自定义图片上传的方式,意思是点击这个图片按钮的时候,会出发一个回调,可以在回调里触发自己的文件上传开关。这里我用的文件上传是antd-vue的a-upload属性。

quill-quill-editor:

    <quill-editor 
      v-model="message" 
      :options="editorOption" 
      @change="change">
        <div id="toolbar" slot="toolbar"></div>
    </quill-editor>

参数:

      editorOption: {
        modules: {
          toolbar: {
            container: [
              ["bold", "italic", "underline", "strike"], //加粗,斜体,下划线,删除线
              ["blockquote", "code-block"], //引用,代码块
              [{ header: 1 }, { header: 2 }], // 标题,键值对的形式;1、2表示字体大小
              [{ list: "ordered" }, { list: "bullet" }], //列表
              [{ script: "sub" }, { script: "super" }], // 上下标
              [{ indent: "-1" }, { indent: "+1" }], // 缩进
              [{ direction: "rtl" }], // 文本方向
              [{ size: ["small", false, "large", "huge"] }], // 字体大小
              [{ header: [1, 2, 3, 4, 5, 6, false] }], //几级标题
              [{ color: [] }, { background: [] }], // 字体颜色,字体背景颜色
              [{ font: [] }], //字体
              [{ align: [] }], //对齐方式
              ["clean"], //清除字体样式
              ["image"], //上传图片
            ],
            handlers: {
              image: (value) => {
                if (value) {
           // 触发antd-vue的modal对话框
this.visible = true; } else { this.quill.format("image", false
); } }, }, }, syntax: { highlight: (text) => hljs.highlightAuto(text).value, }, }, },

说明:

  • 这里的思路是当点击图片按钮时,显示antd-vue的对话框,上传组件就放在对话框中
  • 通过上传组件选择图片,并通过后端给的上传接口获取返回的地址
  • 然后把返回的地址使用字符串处理把img的src动态拼接到内容中

对话框:

    <a-modal
      title="选择图片"
      :visible="visible"
      @ok="handleOk"
      @cancel="handleCancel"
      :closable="false"
      okText="确定"
      cancelText="取消"
      :file-list="fileList"
      :before-upload="beforeUpload"
    >
      <a-upload
        class="pdupload"
        name="file"
        :multiple="false"
        :action="$api.upload"
        @change="handleChange1"
        accept=".jpg, .jpeg, .png, .webp"
        :fileList="fl"
      >
        <a-button>
          <a-icon type="upload" />选择图片
        </a-button>
        <span style="padding-left: 15px;color:#888;font-size:12px;">最多一次上传1张图片</span>
      </a-upload>
    </a-modal>
    handleChange1(info) {
      console.log("图片", info);
      if (info.fileList.length > 1) {
        this.$message.warning("每次仅能上传一张图片!");
        return;
      }
      this.fl = info.fileList;
      if (info.file.status !== "uploading") {
        console.log(info.file, info.fileList);
      }
      if (info.file.status === "done") {
        this.detailImage = info.file.response.response.file_url;
        this.$message.success(`${info.file.name}上传成功`);
      } else if (info.file.status === "error") {
        this.$message.error(`${info.file.name}上传失败`);
      }
    },
    handleOk() {
      this.visible = false;
      // 把图片用img标签的形式添加到详情中
      console.log("结束标签所处位置", this.message.lastIndexOf("</p>"));
      if (this.detailImage) {
        let n = this.message.lastIndexOf("</p>");
        let s = this.message;
        let s1 = s.substring(0, n);
        let domS = `<img src='${this.detailImage}'/></p>`;
        s1 += domS;
        this.message = s1;
      }
      // 清空已经选择的图片
      this.fl = [];
      this.detailImage = "";
    },
    handleCancel() {
      this.visible = false;
    }

组件源码

<template>
  <div class="pro_detail">
    <!-- 产品详情组件 -->
    <common-tit title="产品详情"></common-tit>
    <quill-editor 
      v-model="message" 
      :options="editorOption" 
      @change="change">
        <div id="toolbar" slot="toolbar"></div>
    </quill-editor>
    <a-modal
      title="选择图片"
      :visible="visible"
      @ok="handleOk"
      @cancel="handleCancel"
      :closable="false"
      okText="确定"
      cancelText="取消"
      :file-list="fileList"
      :before-upload="beforeUpload"
    >
      <a-upload
        class="pdupload"
        name="file"
        :multiple="false"
        :action="$api.upload"
        @change="handleChange1"
        accept=".jpg, .jpeg, .png, .webp"
        :fileList="fl"
      >
        <a-button>
          <a-icon type="upload" />选择图片
        </a-button>
        <span style="padding-left: 15px;color:#888;font-size:12px;">最多一次上传1张图片</span>
      </a-upload>
    </a-modal>
  </div>
</template>

<script>
import CommonTit from "../CommonTit";

export default {
  components: { CommonTit },
  props: ["proDetail"],
  data() {
    return {
      fl: [],
      visible: false,
      previewVisible: false,
      detailImage: "",
      message: "",
      editorOption: {
        modules: {
          toolbar: {
            container: [
              ["bold", "italic", "underline", "strike"], //加粗,斜体,下划线,删除线
              ["blockquote", "code-block"], //引用,代码块
              [{ header: 1 }, { header: 2 }], // 标题,键值对的形式;1、2表示字体大小
              [{ list: "ordered" }, { list: "bullet" }], //列表
              [{ script: "sub" }, { script: "super" }], // 上下标
              [{ indent: "-1" }, { indent: "+1" }], // 缩进
              [{ direction: "rtl" }], // 文本方向
              [{ size: ["small", false, "large", "huge"] }], // 字体大小
              [{ header: [1, 2, 3, 4, 5, 6, false] }], //几级标题
              [{ color: [] }, { background: [] }], // 字体颜色,字体背景颜色
              [{ font: [] }], //字体
              [{ align: [] }], //对齐方式
              ["clean"], //清除字体样式
              ["image"], //上传图片
            ],
            handlers: {
              image: (value) => {
                if (value) {
                  this.visible = true;
                } else {
                  this.quill.format("image", false);
                }
              },
            },
          },
          syntax: {
            highlight: (text) => hljs.highlightAuto(text).value,
          },
        },
      },
    };
  },
  methods: {
    change() {
      console.log(this.message);
      this.$emit("update:proDetail", this.message);
    },
    handleChange1(info) {
      console.log("图片", info);
      if (info.fileList.length > 1) {
        this.$message.warning("每次仅能上传一张图片!");
        return;
      }
      this.fl = info.fileList;
      if (info.file.status !== "uploading") {
        console.log(info.file, info.fileList);
      }
      if (info.file.status === "done") {
        this.detailImage = info.file.response.response.file_url;
        this.$message.success(`${info.file.name}上传成功`);
      } else if (info.file.status === "error") {
        this.$message.error(`${info.file.name}上传失败`);
      }
    },
    handleOk() {
      this.visible = false;
      // 把图片用img标签的形式添加到详情中
      console.log("当前内容:", this.message);
      console.log("结束标签所处位置", this.message.lastIndexOf("</p>"));
      if (this.detailImage) {
        let n = this.message.lastIndexOf("</p>");
        let s = this.message;
        let s1 = s.substring(0, n);
        let domS = `<img src='${this.detailImage}'/></p>`;
        s1 += domS;
        this.message = s1;
      }
      // 清空已经选择的图片
      this.fl = [];
      this.detailImage = "";
    },
    handleCancel() {
      this.visible = false;
    },
  },
  mounted() {
    this.message = this.proDetail;
  },
};
</script>

<style lang="scss" scoped>
.pro_detail {
  height: 594px !important;
  border-bottom- 0;
  .quill-editor {
    text-align: left;
    height: 491px;
    >>> .ql-toolbar .ql-formats {
      margin-right: 0;
    }
  }
  >>> .ant-upload {
    display: flex;
    flex-direction: column;
  }
}
</style>
原文地址:https://www.cnblogs.com/codexlx/p/13597070.html