vue实现富文本编辑器上传(粘贴)图片 + 文字

安装插件

npm install vue-quill-editor -s

在使用vue-quill-editor富文本的时候,对于图片的处理经常是将图片转换成base64,再上传数据库,但是base64不好存储。
原理:首先将图片上传服务器,再将图片插入到富文本中,同时光标后移一位。
安装插件

npm install quill-image-extend-module --save-dev

引用:全局引用在main.js中,不过我的是页面引用

import { quillEditor, Quill } from “vue-quill-editor”;
import { container, ImageExtend } from “quill-image-extend-module”;
Quill.register(“modules/ImageExtend”, ImageExtend);
components: { quillEditor },

样式引用

import “quill/dist/quill.core.css”;
import “quill/dist/quill.snow.css”;
import “quill/dist/quill.bubble.css”;

代码

<quill-editor
      element-loading-text="视频正在上传"
      ref="myQuillEditor"
      v-model="myContent"
      :options="editorOption"
      @blur="onEditorBlur($event)"
      @focus="onEditorFocus($event)"
      @change="onEditorChange($event)"
    ></quill-editor>
    <input
      type="file"
      accept=".png, .jpg, .jpeg"
      @change="change"
      id="upload"
      style="display: none"
    />

data中

 editorOption: {
        //富文本配置项
        placeholder: "编辑文章内容",
        theme: "snow",
        modules: {
          ImageExtend: {},
          toolbar: {
            container: container,
            //拦截
            handlers: {
              image: function(value) {
                if (value) {
                  document.querySelector("#upload").click(); // 劫持原来的图片点击按钮事件
                }
              }
            }
          }
        }
      }

图片粘贴上传

 mounted() {
    //  自定义粘贴图片功能  其中UploadOneImg是自己封装的接口,也就是后端接口
    let quill = this.$refs.myQuillEditor.quill;
    this.$forceUpdate();
    quill.root.addEventListener(
      "paste",
      evt => {
        if (
          evt.clipboardData &&
          evt.clipboardData.files &&
          evt.clipboardData.files.length
        ) {
          evt.preventDefault();
          [].forEach.call(evt.clipboardData.files, file => {
            if (!file.type.match(/^image\/(gif|jpe?g|a?png|bmp)/i)) {
              return;
            }
            const formData = new FormData();
            formData.append("pictureFile", file);
            UploadOneImg(formData)
              .then(res => {
                console.log("res", res);
                let quill = this.$refs.myQuillEditor.quill;
                if (res.status == 0) {
                  let length = quill.getSelection().index; //光标位置
                  quill.insertEmbed(length, "image", res.data); // 插入图片  图片地址
                  quill.setSelection(length + 1); //光标后移一位   调整光标到最后
                }
              })
              .catch(err => {
                console.error(err);
              });
          });
        }
      },
      false
    );
  },

图片上传

//makdown上传图片
    change(e) {
      let file = e.target.files[0];
      const formData = new FormData();
      formData.append("pictureFile", file);
      UploadOneImg(formData)
        .then(res => {
          let quill = this.$refs.myQuillEditor.quill;
          if (res.status == 0) {
            let length = quill.getSelection().index; //光标位置
            // 插入图片  图片地址
            quill.insertEmbed(length, "image", res.data);
            // 调整光标到最后
            quill.setSelection(length + 1); //光标后移一位
          }
        })
        .catch(err => {
          console.error(err);
        });
    },

完整代码

<template>
  <div>
    <p class="xuanRan" v-html="vHtml" @click="showImg($event)"></p>
    <div class="imgDolg" v-show="imgPreview.show" @click.stop="imgPreview.show = false">
      <i class="el-icon-close" id="imgDolgClose" @click.stop="imgPreview.show = false"></i>
      <img @click.stop="imgPreview.show = true" :src="imgPreview.img" />
    </div>
    <quill-editor
      element-loading-text="视频正在上传"
      ref="myQuillEditor"
      v-model="myContent"
      :options="editorOption"
      @blur="onEditorBlur($event)"
      @focus="onEditorFocus($event)"
      @change="onEditorChange($event)"
    ></quill-editor>
    <input
      type="file"
      accept=".png, .jpg, .jpeg"
      @change="change"
      id="upload"
      style="display: none"
    />
    <div style="text-align:right">
      <el-button @click="onSubmit" type="primary" style="margin-top:10px;">提交</el-button>
    </div>
  </div>
</template>
 
<script>
import {
  UploadOneImg,
  clientText,
  clientTextData
} from "../../api/salesPerson.js";
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
import { quillEditor, Quill } from "vue-quill-editor";
import { container, ImageExtend } from "quill-image-extend-module";
Quill.register("modules/ImageExtend", ImageExtend);
export default {
  name: "Quill",
  components: { quillEditor },
  props: {
    content: {
      type: String,
      default: ""
    }
  },
  data() {
    return {
      // 图片放大
      imgPreview: {
        img: "",
        show: false
      },
      vHtml: "",
      myContent: this.content, // 富文本
      editorOption: {
        //富文本配置项
        placeholder: "编辑文章内容",
        theme: "snow",
        modules: {
          ImageExtend: {},
          toolbar: {
            container: container,
            //拦截
            handlers: {
              image: function(value) {
                if (value) {
                  document.querySelector("#upload").click(); // 劫持原来的图片点击按钮事件
                }
              }
            }
          }
        }
      }
    };
  },
  props: ["clientId"],
  watch: {
    content() {
      this.myContent = this.content;
    }
  },
  mounted() {
    //  图片粘贴
    let quill = this.$refs.myQuillEditor.quill;
    this.$forceUpdate();
    quill.root.addEventListener(
      "paste",
      evt => {
        if (
          evt.clipboardData &&
          evt.clipboardData.files &&
          evt.clipboardData.files.length
        ) {
          evt.preventDefault();
          [].forEach.call(evt.clipboardData.files, file => {
            if (!file.type.match(/^image\/(gif|jpe?g|a?png|bmp)/i)) {
              return;
            }
            const formData = new FormData();
            formData.append("pictureFile", file);
            UploadOneImg(formData)
              .then(res => {
                console.log("res", res);
                let quill = this.$refs.myQuillEditor.quill;
                if (res.status == 0) {
                  let length = quill.getSelection().index; //光标位置
                  quill.insertEmbed(length, "image", res.data); // 插入图片  图片地址
                  quill.setSelection(length + 1); //光标后移一位   调整光标到最后
                }
              })
              .catch(err => {
                console.error(err);
              });
          });
        }
      },
      false
    );
  },
  created() {},
  methods: {
    // 图片点击放大
    showImg(e) {
      if (e.target.tagName == "IMG") {
        this.imgPreview.img = e.target.src;
        this.imgPreview.show = true;
      }
    },
    // 富文本渲染
    richTextrendering() {
      clientTextData({
        url: "front_rear_api/aaaaaa",
        user_id: this.$store.getters.userid,
        token: this.$store.getters.token,
        client_id: this.clientId
      })
        .then(res => {
          if (res.status != 0) {
            this.$message.error(res.msg);
          } else {
            this.vHtml = res.data.content;
          }
        })
        .catch(err => {
          console.log(err);
        });
    },
    //上传图片
    change(e) {
      let file = e.target.files[0];
      const formData = new FormData();
      formData.append("pictureFile", file);
      UploadOneImg(formData)
        .then(res => {
          let quill = this.$refs.myQuillEditor.quill;
          if (res.status == 0) {
            let length = quill.getSelection().index; //光标位置  
            quill.insertEmbed(length, "image", res.data);// 插入图片  图片地址
            quill.setSelection(length + 1); //光标后移一位  调整光标到最后
          }
        })
        .catch(err => {
          console.error(err);
        });
    },
    // 失去焦点事件
    onEditorBlur() {
      this.$emit("onEditorBlur", this.myContent);
    },
    // 获得焦点事件
    onEditorFocus() {
      this.$emit("onEditorFocus", this.myContent);
    },
    // 内容改变事件
    onEditorChange() {
      this.$emit("onEditorChange", this.myContent);
    },
    onSubmit() {
      if (this.myContent) {
        clientText({
          url: "front_rear_api/aaaa",
          user_id: this.$store.getters.userid,
          token: this.$store.getters.token,
          client_id: this.clientId,
          content: this.myContent
        })
          .then(res => {
            if (res.status != 0) {
              this.$message.error(res.msg);
            } else {
              this.$message.success(res.msg);
              this.richTextrendering();
              this.myContent = "";
            }
          })
          .catch(err => {
            console.log(err);
          });
      } else {
        this.$message.error("内容不能为空");
      }
    }
  }
};
</script>
 <style>
.ql-formats:nth-of-type(2),
.ql-formats:nth-of-type(3),
.ql-formats:nth-of-type(4),
.ql-formats:nth-of-type(5),
.ql-formats:nth-of-type(6),
.ql-formats:nth-of-type(7),
.ql-formats:nth-of-type(8),
.ql-formats:nth-of-type(9),
.ql-formats:nth-of-type(11),
.ql-formats:nth-of-type(12),
.ql-formats:nth-of-type(13) {
  display: none !important;
}
.ql-video,
.ql-link {
  display: none !important;
}
.ql-snow .ql-editor img {
  width: 30% !important;
  height: 30% !important;
}
/* 富文本编辑器 */
.editor {
  line-height: normal !important;
}
.ql-editor {
  min-height: 500px;
}
</style>
<style lang="scss" >
/* 这里是渲染图片放大的样式 */
.xuanRan {
  p,div,span{font-size: 16px !important;}
  img {width: 30% !important; }
}
.imgDolg {
  width: 100vw;
  height: 100vh;
  position: fixed;
  z-index: 9999;
  background-color: rgba(140, 134, 134, 0.6);
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  #imgDolgClose {
    position: fixed;
    top: 35px;
    cursor: pointer;
    right: 7%;
    font-size: 50px;
    color: white;
  }
  img {
    width: 50%;
  }
}
</style>
Logo

前往低代码交流专区

更多推荐