1、自定义图片上传

需求:

  • 因为在展示页面使用到了vue-photo-preview组件实现点击图片预览,所以需要修改image.ts进行修改添加预览组件需要的previewpreview-text属性,效果图如下:
    上传图片添加属性
  • 展示页面点击图片预览:
    在这里插入图片描述实现方法:
  1. 到quill到github:https://github.com/quilljs/quill/tree/develop复制image.ts到自己新建的image.js进行改写create,image.ts路径:packages/quill/src/formats/image.ts
    image.js修改处
    	  static create(value) {
    	    const node = super.create(value);
    	    if (typeof value === "string") {
    	      // 保留原来的图片方法
    	      node.setAttribute("src", this.sanitize(value));
    	    } else {
    	      // 自定义图片方法
    	      node.setAttribute("src", value.src);
    	      // 使用了vue-photo-preview,所以添加preview,preview-text这两个属性
    	      node.setAttribute("preview", "1"); //preview相同的为一组,这里所有上传图片为一组
    	      node.setAttribute("preview-text", value.title); //图片名称,预览时显示使用
    	    }
    	    return node;
    	  }
    	```
    
  • image.js完整代码:
    import Quill from "quill";
    let EmbedBlot = Quill.import("formats/image");
    //添加style,解决重进编辑器ima标签丢掉style属性问题
    const ATTRIBUTES = ["alt", "height", "width", "style"];
    
    class Image extends EmbedBlot {
      static blotName = "image";
      static tagName = "IMG";
    
      static create(value) {
        const node = super.create(value);
        if (typeof value === "string") {
          // 保留原来的图片方法
          node.setAttribute("src", this.sanitize(value));
        } else {
          // 自定义图片方法
          node.setAttribute("src", value.src);
          // 使用了vue-photo-preview所以添加preview,preview-text这两个属性
          node.setAttribute("preview", "1"); //preview相同的为一组
          node.setAttribute("preview-text", value.title); //图片名称,预览时显示使用
        }
        return node;
      }
    
      static formats(domNode) {
        return ATTRIBUTES.reduce((formats, attribute) => {
          if (domNode.hasAttribute(attribute)) {
            formats[attribute] = domNode.getAttribute(attribute);
          }
          return formats;
        }, {});
      }
    
      static match(url) {
        return /\.(jpe?g|gif|png)$/.test(url) || /^data:image\/.+;base64/.test(url);
      }
    
      static register() {
        if (/Firefox/i.test(navigator.userAgent)) {
          setTimeout(() => {
            // Disable image resizing in Firefox
            // @ts-expect-error
            document.execCommand("enableObjectResizing", false, false);
          }, 1);
        }
      }
    
      static sanitize(url) {
        return sanitize(url, ["http", "https", "data"]) ? url : "//:0";
      }
    
      static value(domNode) {
        return domNode.getAttribute("src");
      }
    
      format(name, value) {
        if (ATTRIBUTES.indexOf(name) > -1) {
          if (value) {
            this.domNode.setAttribute(name, value);
          } else {
            this.domNode.removeAttribute(name);
          }
        } else {
          super.format(name, value);
        }
      }
    }
    function sanitize(url, protocols) {
      const anchor = document.createElement("a");
      anchor.href = url;
      const protocol = anchor.href.slice(0, anchor.href.indexOf(":"));
      return protocols.indexOf(protocol) > -1;
    }
    
    export default Image;
    
    
  1. vue页面引入image.js
    import Quill from "quill";
    import Image from "./image";
    Quill.register(Image, true);
    
  2. 修改el-upload组件上传成功后回调函数中的quill.insertEmbed()传参,
        handleUploadSuccess(res, file) {
      // 获取富文本组件实例
      let quill = this.Quill;
      // 如果上传成功
      if (res.code === 200) {
        let shiftLength = 1;
        if (this.uploadType == "image") {
          // 插入图片  res.url为服务器返回的图片地址
          quill.insertEmbed(this.lastSelection, "image", {
            src: process.env.VUE_APP_BASE_API + res.data.fileAddress, //上传图片后端返回地址
            title: res.data.originalName, //上传图片名称
          });
        } 
        // 调整光标到最后
        quill.setSelection(this.lastSelection + shiftLength);
        this.$modal.closeLoading();
      } else {
        this.$modal.closeLoading();
        this.$modal.msgError("上传失败,请重试");
      }
    },
    

2、使用quill-image-resize-module插件修改上传的图片尺寸,对齐方式

1. 安装
npm install quill-image-resize-module -- save
2. 引用报错问题解决
  • 报错Cannot read properties of undefined (reading 'impoerts')
    在这里插入图片描述
  • 解决办法:修改vue.config.js,添加配置
    // 20230801添加ts配置
    configureWebpack: {
    // 添加配置解决vue 引入quill - image - resize - module 插件报错
    	plugins: [
          new webpack.ProvidePlugin({
            "window.Quill": "quill/dist/quill.js",
            Quill: "quill/dist/quill.js",
          }),
      ],
    },
    
  • 报错quill Cannot import modules/imageResize. Are you sure it was registered?
    在这里插入图片描述
  • 解决方法:不要在组件内引入插件注册,在main.js内引入并且注册
    javascript // 富文本上传图片调整大小 import Quill from "quill"; import imageResize from "quill-image-resize-module"; // 调整大小组件。 window.Quill = Quill; Quill.register("modules/imageResize", imageResize);
3. 在vue页面添加quill配置项imageResize
	 options: {
        theme: "snow",
        bounds: document.body,
        debug: "warn",
        modules: {
          // 工具栏配置
          toolbar: {
          container: [],
          handlers: {},
          imageResize: {
            //放大缩小
            displayStyles: {
              backgroundColor: "black",
              border: "none",
              color: "white",
            },
            modules: ["Resize", "DisplaySize", "Toolbar"],
            // Resize: 允许缩放、DisplaySize:缩放是显示像素、Toolbar:显示工具栏,用于设置图片居中等样式
          },
          // imageDrop: true, //图片拖拽
        },
        placeholder: "请输入内容",
        readOnly: this.readOnly,
      },

3、重新进入编辑器img标签丢失style属性

  • 在修改的image.js添加‘style’属性即可
    //添加style,解决重进编辑器ima标签丢掉style属性问题
    const ATTRIBUTES = ["alt", "height", "width", "style"];
    

4、监测粘贴的是图片上传到后端

  • 初始化quill编辑器时,添加监听粘贴事件
	// 添加监听事件
	editor.addEventListener("paste", this.handlePaste, true);
    /** 监听粘贴 -如果是图片则将图片上传到服务器*/
    handlePaste(evt) {
      if (
        evt.clipboardData &&
        evt.clipboardData.files &&
        evt.clipboardData.files.length
      ) {
        evt.preventDefault();
        [].forEach.call(evt.clipboardData.files, (file) => {
          // 判断粘贴的是否是图片,不是图片则return
          if (!file.type.match(/^image\/*/i)) {
            return;
          }
          const formData = new FormData();
          formData.append("file", file); //后台上传接口的参数名
          // 获取光标所在位置
          let quill = this.Quill;
          if (!(quill.selection && quill.selection.savedRange)) {
            this.$modal.msgError("上传失败,请重试");
            return;
          }
          this.lastSelection = quill.selection.savedRange.index;
          this.$modal.loading("正在上传文件,请稍候...");
          this.uploadType = "image";
          // 实现上传
          upload(formData)
            .then((res) => {
              // 调用上传成功回调函数
              this.handleUploadSuccess(res);
            })
            .catch((error) => {
              //上传失败回调
              this.handleUploadError();
            });
        });
      }
    },
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐