<template>
<div>
<quill-editor
:key="key"
ref="myEditor"
v-model="content"
class="editor"
:options="editorOption"
:disabled="disabled"
@change="onEditorChange($event)"
/>
<el-upload
style="display: none"
:class="className"
:action="serverUrl"
accept=".doc,.docx,.xls,.xlsx,.csv,.ppt,.pptx,.gif,.jpg,.jpeg,.png,.bmp,.zip,.rar,.war,.jar,.tar"
name="file"
:headers="headers"
:show-file-list="false"
:before-upload="beforeUpload"
:on-success="upload"
/>
</div>
</template>
<script>
import 'quill/dist/quill.snow.css'
import { tokenName, baseURL } from '@/config'
import { quillEditor, Quill } from 'vue-quill-editor'
import { container, ImageExtend, QuillWatch } from './ImageExtend'
import ImageResize from 'quill-image-resize-module'
let timer
let Link = Quill.import('formats/link')
class MyLink extends Link {
static create(value) {
let node = undefined
if (value && !value.href) {
node = super.create(value)
} else {
node = super.create(value.href.link)
node.innerText = value.innerText
node.download = value.innerText
}
return node
}
}
MyLink.blotName = 'link'
MyLink.tagName = 'A'
Quill.register('modules/imageResize', ImageResize)
Quill.register('modules/ImageExtend', ImageExtend)
Quill.register(MyLink)
export default {
name: 'QuillEditor',
components: { quillEditor },
props: {
value: {
type: String,
default: '',
},
placeholder: {
type: String,
default: '请输入正文',
},
disabled: {
type: Boolean,
default: false,
},
self: {
type: Object,
default: () => {
return {}
},
},
},
data() {
return {
key: 1,
content: this.value,
keepValue: '',
className: 'uploadFile' + this.self.index,
config: {
headers: {
'Blade-Auth': this.$baseToken(),
'Content-Type': 'multipart/form-data',
Authorization: 'Basic c3dvcmQ6c3dvcmRfc2VjcmV0',
},
},
serverUrl: baseURL + '/blade-resource/oss/endpoint/put-file-attach',
headers: {
[tokenName]: this.$baseToken(),
Authorization: 'Basic c3dvcmQ6c3dvcmRfc2VjcmV0',
},
editorOption: {
theme: 'snow',
placeholder: this.placeholder,
className: 'uploadFile' + this.self.index,
modules: {
imageResize: {
displayStyles: {
backgroundColor: 'black',
border: 'none',
color: 'white',
},
modules: ['Resize', 'DisplaySize', 'Toolbar'],
},
ImageExtend: {
name: 'file',
action: baseURL + '/blade-resource/oss/endpoint/put-file-attach',
headers: (xhr) => {
xhr.setRequestHeader('Authorization', 'Basic c3dvcmQ6c3dvcmRfc2VjcmV0')
xhr.setRequestHeader(tokenName, this.$baseToken())
return xhr
},
response: (res) => res.data.link,
},
toolbar: {
container: container,
handlers: {
image() {
QuillWatch.emit(this.quill.id)
},
upload(value) {
if (value) {
let className = '.' + this.quill.options.className + ' input'
document.querySelector(className).click()
}
},
},
},
clipboard: {
matchers: [['img', this.handleCustomMatcher]],
},
},
},
}
},
watch: {
value(val) {
if (this.keepValue !== val) this.content = val
},
placeholder(val) {
this.editorOption.placeholder = val
this.key++
this.$nextTick(() => {
let num = this.editorOption.placeholder.split('\n').length
if (num > 3) {
document.getElementsByClassName('ql-editor')[0].style.minHeight = 80 + num * 14 + 'px'
}
})
},
},
methods: {
onEditorChange({ html }) {
clearTimeout(timer)
timer = setTimeout(() => {
html = html.replace(//g, '')
this.keepValue = html
this.$emit('input', html)
this.$emit('getVal', html)
}, 300)
},
handleCustomMatcher(node, Delta) {
let ops = []
ops = Delta.ops.filter((op) => op.insert.image.indexOf('base64') === -1)
Delta.ops = ops
return Delta
},
upload(res, file) {
let quill = this.$refs.myEditor.quill
if (res.code === 200) {
let fileNameLength = file.name.length
let length = quill.getSelection().index
quill.insertEmbed(length, 'link', { href: res.data, innerText: file.name })
quill.setSelection(length + fileNameLength)
} else {
this.$message.error('插入失败')
}
},
beforeUpload(file) {
if (file.size / 1024 / 1024 > 10) {
this.$baseMessage('error', `上传文件大小超出限制`)
}
return
},
},
}
</script>
<style lang="scss">
.editor {
line-height: 1.42;
}
.ql-editor {
min-height: 150px;
}
.ql-toolbar.ql-snow,
.ql-container.ql-snow {
border: 1px solid #dcdfe6;
}
.ql-snow .ql-tooltip[data-mode='link']::before {
content: '请输入完整链接:';
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
padding-right: 0;
content: '保存';
border-right: 0;
}
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
content: '14px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='small']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='small']::before {
content: '10px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='large']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='large']::before {
content: '18px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='huge']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='huge']::before {
content: '32px';
}
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
content: '文本';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='1']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='1']::before {
content: '标题1';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='2']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='2']::before {
content: '标题2';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='3']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='3']::before {
content: '标题3';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='4']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='4']::before {
content: '标题4';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='5']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='5']::before {
content: '标题5';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='6']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='6']::before {
content: '标题6';
}
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
content: '标准字体';
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='serif']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='serif']::before {
content: '衬线字体';
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='monospace']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='monospace']::before {
content: '等宽字体';
}
.quill-editor .ql-snow.ql-toolbar .ql-formats .ql-upload {
background-image: url('./img/upload-2-line.svg') !important;
background-size: 18px 18px;
background-position: center center;
background-repeat: no-repeat;
}
</style>