Vue3 QuillEditor 富文本编辑器
对于这个组件,我是又爱又恨,上代码:
<template>
<div>
<!-- 此处注意写法v-model:content -->
<QuillEditor ref="myQuillEditor" theme="snow" :content="content" :options="data.editorOption" contentType="html"
@update:content="setValue" />
<!-- 使用自定义图片上传 -->
<input type="file" hidden accept=".jpg,.png" ref="fileBtn" @change="handleUpload" />
</div>
</template>
<script setup>
import { QuillEditor, Quill } from '@vueup/vue-quill'
import '@vueup/vue-quill/dist/vue-quill.snow.css'
import { uploadSingleFile } from '@/api/upload'
const props = defineProps(['value'])
const emit = defineEmits(['update:value'])
const myQuillEditor = ref()
const content = ref('')
const fileBtn = ref()
const toolBarOption = [
['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线
["blockquote", "code-block"], // 引用
[{ 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'], // 清除文本格式
['link', 'image'] // 链接、图片、视频video
]
const data = reactive({
content: '',
editorOption: {
modules: {
toolbar: toolBarOption
},
placeholder: '请输入内容...'
}
})
const imgHandler = (state) => {
if (state) {
fileBtn.value.click()
}
}
// 抛出更改内容,此处避免出错直接使用文档提供的getHTML方法
const setValue = () => {
const text = toRaw(myQuillEditor.value).getHTML()
emit('update:value', text)
}
const handleUpload = (e) => {
const files = Array.prototype.slice.call(e.target.files)
if (!files) {
return
}
const formdata = new FormData()
formdata.append('file', files[0])
uploadSingleFile(formdata).then(res => {
if (res.code == 200 && res.data) {
const quill = toRaw(myQuillEditor.value).getQuill()
const length = quill.getSelection().index
quill.insertEmbed(length, 'image', res.data.url)
quill.setSelection(length + 1)
} else {
proxy.$modal.msgError(res.msg || '发生错误,请稍后重试!')
}
})
}
// 初始化编辑器
onMounted(async () => {
const quill = toRaw(myQuillEditor.value).getQuill()
if (myQuillEditor.value) {
quill.getModule('toolbar').addHandler('image', imgHandler)
await nextTick()
// TODO fix bug 无法渲染 初始值
setTimeout(() => {
myQuillEditor.value.setContents(props.value)
}, 300)
}
})
</script>
<style scoped lang="scss">
:deep(.ql-container) {
height: 400px;
line-height: normal;
width: auto;
}
:deep(span.ql-size) {
max-width: 80px !important;
}
:deep(.ql-tooltip[data-mode="link"]::before) {
content: "请输入链接地址:";
}
:deep(.ql-snow .ql-tooltip.ql-editing a.ql-action::after) {
content: "保存";
}
:deep(.ql-snow .ql-tooltip a.ql-action::after) {
content: "编辑";
}
:deep(.ql-snow .ql-tooltip a.ql-remove::before) {
content: "移除";
}
:deep(.ql-snow .ql-tooltip::before) {
content: "链接地址:";
}
:deep(.ql-snow .ql-tooltip[data-mode=link]::before) {
content: "请输入链接地址:";
}
:deep(.ql-tooltip[data-mode="video"]) {
left: 0 !important;
}
:deep(.ql-tooltip[data-mode="video"]::before) {
content: "请输入视频地址:";
}
:deep(.ql-picker.ql-size .ql-picker-label::before,
.ql-picker.ql-size .ql-picker-item::before) {
content: "14px";
}
:deep(.ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
.ql-picker.ql-size .ql-picker-item[data-value="small"]::before) {
content: "10px";
}
:deep(.ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
.ql-picker.ql-size .ql-picker-item[data-value="large"]::before) {
content: "18px";
}
:deep(.ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
.ql-picker.ql-size .ql-picker-item[data-value="huge"]::before) {
content: "32px";
}
:deep(.ql-picker.ql-header .ql-picker-label::before,
.ql-picker.ql-header .ql-picker-item::before) {
content: "文本";
}
:deep(.ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-picker.ql-header .ql-picker-item[data-value="1"]::before) {
content: "标题1";
}
:deep(.ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-picker.ql-header .ql-picker-item[data-value="2"]::before) {
content: "标题2";
}
:deep(.ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-picker.ql-header .ql-picker-item[data-value="3"]::before) {
content: "标题3";
}
:deep(.ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-picker.ql-header .ql-picker-item[data-value="4"]::before) {
content: "标题4";
}
:deep(.ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-picker.ql-header .ql-picker-item[data-value="5"]::before) {
content: "标题5";
}
:deep(.ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-picker.ql-header .ql-picker-item[data-value="6"]::before) {
content: "标题6";
}
:deep(.ql-picker.ql-font .ql-picker-label::before,
.ql-picker.ql-font .ql-picker-item::before) {
content: "标准字体";
}
:deep(.ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
.ql-picker.ql-font .ql-picker-item[data-value="serif"]::before) {
content: "衬线字体";
}
:deep(.ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
.ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before) {
content: "等宽字体";
}
:deep(.ql-formats) {
height: 21px;
line-height: 21px;
}
</style>
作者:胡倩倩0903
本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
标签:
富文本编辑器
posted on 2023-05-08 15:37 kitty20180903suzhou 阅读(591) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY