vue3使用vue-quill实现富文本编辑器上传图片

最近开发的一个vue3+element-plus的项目,需要用到富文本编辑器,最终选择了VueQuill这一款轻便型的富文本编辑器:官网地址为
https://vueup.github.io/vue-quill/guide/installation.html

首先,我们把它install下来,执行以下对应命令下载

npm install @vueup/vue-quill@beta --save
# OR
yarn add @vueup/vue-quill@beta

在vue项目的main.js中进行相关的配置

import { createApp } from 'vue'
import { QuillEditor } from '@vueup/vue-quill'
import '@vueup/vue-quill/dist/vue-quill.snow.css';

const app = createApp()
app.component('QuillEditor', QuillEditor)

我个人是将富文本编辑器封装成了公共组件,在components中创建editor.vue公共组件
在这里插入图片描述
引入quillEditor

import { QuillEditor } from '@vueup/vue-quill'
import '@vueup/vue-quill/dist/vue-quill.snow.css';

export default {
  components: {
    QuillEditor
  }
}

在dom中使用

<template>
  <QuillEditor theme="snow" />
</template>

这样一个轻便的vue-quill富文本编辑器就出来了。然而,我们希望得到的数据是html的相关dom标签,希望图片不是以base64的格式保存到dom中,而是通过上传接口获得相应的超链接插入到我们需要的img标签里。这可咋办呢?别急,我们一一来对应。

首先quill输出的文件格式是需要配置的

<QuillEditor
      id="editorId"
      ref="myQuillEditor"
      //绑定数据需要加:content才能绑定成功
      v-model:content="content"
      theme="snow"
      //这里是指定富文本输出的文件,我需要的数据格式是html的,而默认是delta,这里小伙伴们需要特别注意
      contentType="html"
      :options="options"
    />

我们通过element的upload功能来实现上传图片的功能

 <el-upload
      class="editor-img-uploader"
      :action="upLoadUrl"
      :show-file-list="false"
      :headers="headers"
      :on-success="handleAvatarSuccess"
      :before-upload="beforeAvatarUpload"
    >
      <i class="el-icon-plus editor-img-uploader"></i>
    </el-upload>

并将此dom隐藏

<style scoped lang='less'>
.editor-img-uploader {
  display: none;
}
.ql-editor {
  min-height: 300px;
}
</style>

在图片返回成功时通过获得富文本光标的位置动态将img标签插入我们希望它所在的位置

 // 上传成功函数
     // 上传组件获得的图片地址反渲染近富文本中
    function handleSuccess(res) {
      // 获取富文本组件实例
      // 如果上传成功
      if (res) {
        // 获取富文本实例
      let quill = toRaw(myQuillEditor.value).getQuill()
      // 获取光标位置
      let length=quill.selection.savedRange.index;
        // 插入图片,res为服务器返回的图片链接地址
        quill.insertEmbed(length, "image", res);
        // 调整光标到最后
        quill.setSelection(length + 1);
      } else {
        // 提示信息,需引入Message
        ElMessage({
          message: "提交失败!",
          type: "error",
        });
      }
    }

完整代码如下

<template>
  <div style="margin-bottom: 5px; border-radius: 10px">
    <el-upload
      class="editor-img-uploader"
      :action="upLoadUrl"
      :show-file-list="false"
      :headers="headers"
      :on-success="handleAvatarSuccess"
      :before-upload="beforeAvatarUpload"
    >
      <i class="el-icon-plus editor-img-uploader"></i>
    </el-upload>
    <QuillEditor
      id="editorId"
      ref="myQuillEditor"
      v-model:content="content"
      theme="snow"
      contentType="html"
      :options="options"
    />
  </div>
</template>

<script>
import { QuillEditor, Quill } from "@vueup/vue-quill";
import { reactive, ref, toRaw } from "vue";
import config from "../api/config";
import { ElMessage } from "element-plus";
import "@vueup/vue-quill/dist/vue-quill.snow.css";
export default {
  components: { QuillEditor },
  props: {
    // 富文本编辑器
    getContent: { type: String, default: "" },
  },
  setup(props) {
    let content = ref("");
    content.value = props.getContent;
    let upLoadUrl = ref(
      config.baseUrl.product +
        "/api/uploadFileTwo?token=" +
        sessionStorage.getItem("token")
    );
    let headers = reactive({
      token: sessionStorage.getItem("token"),
    });
    const myQuillEditor=ref(null)
    const options = reactive({
      modules: {
        toolbar: {
          container: [
            [{ size: ["small", false, "large"] }],
            ["bold", "italic", "underline"],
            [{ header: 1 }, { header: 2 }],
            [{ list: "ordered" }, { list: "bullet" }],
            ["link", "image"],
            [{ color: [] }, { background: [] }],
            [{ align: [] }]
          ],
          handlers: {
            image: function (value) {
              if (value) {
                // 调用element图片上传
                document
                  .querySelector(".editor-img-uploader>.el-upload")
                  .click();
              } else {
                Quill.format("image", true);
              }
            },
          },
        },
        history: {
          delay: 1000,
          maxStack: 50,
          userOnly: false
        },
      },
    });
    // 图片上传成功返回图片地址
    function handleAvatarSuccess(res, file) {
      // 如果上传成功
      if (res) {
        // 获取富文本实例
        let quill = toRaw(myQuillEditor.value).getQuill();
        // 获取光标位置
        let length = quill.selection.savedRange.index;
        // 插入图片,res为服务器返回的图片链接地址
        quill.insertEmbed(length, "image", res);
        // 调整光标到最后
        quill.setSelection(length + 1);
      } else {
        ElMessage({
          message: "提交失败!",
          type: "error",
        });
      }
    }
    // 图片上传前拦截
    function beforeAvatarUpload(file) {
      const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"];
      const isJPG = type.includes(file.type);
      const isLt2M = file.size / 1024 / 1024 < 2;
      if (!isJPG) {
        ElMessage({
          message: "图片格式错误",
          type: "success",
        });
      }
      if (!isLt2M) {
        ElMessage({
          message: "上传图片不能超过" + size.value + "M",
          type: "success",
        });
      }
      return isJPG && isLt2M;
    }
    return {
      options,
      content,
      upLoadUrl,
      headers,
      myQuillEditor,
      handleAvatarSuccess,
      beforeAvatarUpload
    };
  },
};
</script>
<style scoped lang='less'>
.editor-img-uploader {
  display: none;
}
.ql-editor {
  min-height: 300px;
}
</style>

我们如何去使用这个公共组件呢?

 			<editorCom
              v-if="childDom"
              ref="editorRef"
              :getContent="默认值"
            />

要取的时候,我们通过ref来取this.$refs.editorRef.content即可获得值

content:this.$refs.editorRef.content

更新一版,vue3父子组件传值挺香的,之前没找到资料,做完项目来整理代码的时候才发现vue3里面拿值挺简单的,不过使用的地方挺多的,我已经不想动了,咳咳,后面优化项再来优化吧

// 初始化查询数据函数
    const init = async () => {
      const res = await companyInfoList({
        user_id: userInfo.value.user_id,
        id: sessionStorage.getItem("companyId")
      });
      form.value = res.data.response;
      childDom.value = true;
    };

好的,完整思路在这里了,话说,这才2021年,我任务已经排满到2023年是什么情况???(>﹏<。)~呜呜呜……

  • 22
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 28
    评论
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值