最近开发的一个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年是什么情况???(>﹏<。)~呜呜呜……