前置操作:
1.下载:
"quill": "^1.3.7",
"quill-image-resize-module": "^3.0.0",
"vue-quill-editor": "^3.0.6",
2.config配置— vue.config.js (脚手架3.x版本)
chainWebpack (config) {
...
config.plugin('provide').use(webpack.ProvidePlugin, [
{
'window.Quill': 'quill'
}
])
...
}
3.具体代码实现
<template>
<div>
<quill-editor ref="myQuillEditor" v-model="content" class="ql-editor c333" :options="editorOption" @change="onEditorChange" />
<div class="length_wr"> {{ contentLength }}/{{ maxLength }} </div>
<el-upload class="none" :action="'/fhris/file/upload?t='+(+new Date())" accept="image/jpg, image/jpeg, image/png, image/gif" :show-file-list="false" :before-upload="ImgBeforeUpload" :on-success="ImgUploadSuccess" :on-error="ImgUploadError">
<i class="el-icon-plus avatar-uploader-icon upload-editor-el" />
</el-upload>
</div>
</template>
<script>
import { quillEditor } from 'vue-quill-editor' // 调用编辑器
import 'quill/dist/quill.snow.css' // 富文本编辑器外部引用样式
import { upload } from '@/utils/request'
// 扩展部分-调整图片大小
import * as Quill from 'quill' // 富文本基于quill
import resizeImage from 'quill-image-resize-module'
Quill.register('modules/imageResize', resizeImage)
export default {
name: 'BaseQuillEditor',
components: {
quillEditor
},
props: {
propsContent: { // 父组件传值回显
type: String,
default: ''
},
maxLength: { // 字数限制
type: Number,
default: 2000
},
placeholder: {
type: String,
default: '请填写相关说明、内容、原因等...'
},
isImgBase64: { // 图片是否采用base64
type: Boolean,
default: false
}
},
data () {
return {
content: '',
contentLength: 0, // 内容字数
editorOption: {
modules: {
clipboard: this.isImgBase64 ? {} : {
// 粘贴版,处理粘贴时候的自带样式
matchers: [[Node.ELEMENT_NODE, this.HandleCustomMatcher]]
},
imageResize: { // 调整大小组件
displayStyles: {
backgroundColor: 'black',
border: 'none',
color: 'white'
},
modules: ['Resize', 'DisplaySize']
},
toolbar: {
container: [ // 工具栏
['bold', 'italic', 'underline', 'strike'], // 加粗,斜体,下划线,删除线
[{ 'size': ['small', false, 'large', 'huge'] }], // 字体大小
[{ 'list': 'ordered' }, { 'list': 'bullet' }], // 列表
[{ 'indent': '-1' }, { 'indent': '+1' }], // 缩进
[{ 'color': [] }, { 'background': [] }], // 字体颜色,字体背景颜色
[{ 'align': [] }], // 对齐方式
['image'],
['clean'] // 清除字体样式
],
handlers: this.isImgBase64 ? {} : {
'image': (value) => {
if (value) document.querySelector('.upload-editor-el').click() // 点击图片改: 调用图片上传
else this.quill.format('image', false)
}
}
}
},
theme: 'snow',
placeholder: this.placeholder
}
}
},
watch: {
propsContent (v, o) {
this.content = v
const length = this.$refs.myQuillEditor.quill.getLength() - 1 // 字符数
if (this.$route.name.includes('Record') && !o && length !== 1) this.handleCursor() // 解决回显时光标位置错乱问题
}
},
methods: {
handleCursor () {
this.$refs.myQuillEditor.quill.enable(false)
setTimeout(() => {
this.$refs.myQuillEditor.quill.enable(true)
}, 0)
},
onEditorChange (e) {
// 字数限制
this.contentLength <= this.maxLength && this.$emit('getQuillEditorContent', e)
e.quill.deleteText(this.maxLength, 1)
this.contentLength = !this.content ? 0 : this.$refs.myQuillEditor.quill.getLength() - 1 // 默认getLength返回1,因为富文本默认有一个由\n表示的空白行
},
// 粘贴事件
HandleCustomMatcher (node, Delta) {
// 如果是粘贴图片 手动上传 (同步操作插件不支持,粘贴完成后再替换图片)
if (node.src && node.src.includes('data:image/png;base64,')) {
const file = this.dataURLtoBlob(node.src)
const formData = new FormData()
formData.append('file', file, new Date().getTime() + '.png')
this.handleUploadIntoField(formData) // 异步 加入上传图片
Delta.ops = [] // 清除掉粘贴内容
}
const length = Delta?.ops?.[0]?.insert?.length || 0
if (length > 200) Delta.ops[0].insert = Delta?.ops?.[0]?.insert.substring(0, 2000) // 解决粘贴时字数超过限制的问题
return Delta
},
// 粘贴上传图片
handleUploadIntoField (file) {
const options = { url: '/file/upload', method: 'post', data: file }
const header = { 'Content-Type': undefined }
upload(options, header).then(res => {
if (!res.data) {
this.ImgUploadError()
} else {
const quill = this.$refs.myQuillEditor.quill
const length = quill.getSelection().index
const imgUrl = window.location.origin + '/fhris/file/filePreview?id=' + res.data
quill.insertEmbed(length, 'image', imgUrl)
quill.setSelection(length + 1)
}
}, () => {
})
},
dataURLtoBlob (dataurl) {
const arr = dataurl.split(',')
// 注意base64的最后面中括号和引号是不转译的
const _arr = arr[1].substring(0, arr[1].length - 2)
const mime = arr[0].match(/:(.*?);/)[1]
const bstr = atob(_arr)
let n = bstr.length
const u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new Blob([u8arr], { type: mime })
},
// 编辑器内 图片上传前
ImgBeforeUpload (file) {
const isJPG = file.type === 'image/jpg' || file.type === 'image/png' || file.type === 'image/jpeg'
const isLt1M = file.size / 1024 / 1024 < 10
if (!isJPG) this.$message({ type: 'error', message: '支持JPG、PNG格式的图片,大小不得超过10M', showClose: true })
if (!isLt1M) this.$message({ type: 'error', message: '文件最大不得超过10M', showClose: true })
return isJPG && isLt1M
},
// 编辑器内 上传图片成功
ImgUploadSuccess (res, file, list) {
if (res.code + '' !== '200') {
this.ImgUploadError()
} else {
const quill = this.$refs.myQuillEditor.quill
const length = quill.getSelection().index
const imgUrl = window.location.origin + '/fhris/file/filePreview?id=' + res.data
quill.insertEmbed(length, 'image', imgUrl)
quill.setSelection(length + 1)
}
},
// 编辑器内 上传图片失败
ImgUploadError (res, file, list) {
this.$message({ type: 'error', message: '图片插入失败', showClose: true })
}
}
}
</script>
<style lang="scss" scoped>
.ql-editor {
padding: 0;
white-space: normal;
>>> .ql-editor {
min-height: 200px;
padding-bottom: 30px;
}
>>> .ql-container {
font-size: 14px;
min-height: 210px;
border-radius: 0 0 4px 4px;
border-color: #dcdfe6;
}
>>> .ql-toolbar {
border-radius: 4px 4px 0 0;
border-color: #dcdfe6;
}
>>> .ql-blank::before {
font-style: normal;
color: #999;
}
}
.length_wr {
position: absolute;
bottom: 0;
right: 10px;
}
.none {
display: none;
}
</style>
本文介绍了如何在Vue项目中使用vue-quill-editor富文本编辑器,包括图片处理(base64或自定义上传)以及设置最大字数限制等功能。首先,通过下载并配置vue.config.js文件进行初始设置,然后详细展示了代码实现过程。

169

被折叠的 条评论
为什么被折叠?



