• 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>
  • 相关阅读:
    Project Euler 99:Largest exponential 最大的幂
    Project Euler 98:Anagramic squares 重排平方数
    Project Euler 97 :Large non-Mersenne prime 非梅森大素数
    Project Euler 96:Su Doku 数独
    Project Euler 95:Amicable chains 亲和数链
    Project Euler 94:Almost equilateral triangles 几乎等边的三角形
    Project Euler 93:Arithmetic expressions 算术表达式
    Project Euler 92:Square digit chains 平方数字链
    Project Euler 91:Right triangles with integer coordinates 格点直角三角形
    Project Euler 90:Cube digit pairs 立方体数字对
  • 原文地址:https://www.cnblogs.com/codexlx/p/13597070.html
Copyright © 2020-2023  润新知