1.不管粘贴图片的问题
富文本编辑器默认的方式是图片转成base64 但是这个一张图片可能就把后台的默认字符长度占满了 所以需要先服务端上传图片的方式 代码如下
封装组件的方式应该复制了是能直接使用的
<template>
<div class="vue-quill-editor-com">
<quill-editor v-model="content" ref="myQuillEditor" :options="editorOption" @blur="onEditorBlur($event)"
@focus="onEditorFocus($event)" @change="onEditorChange($event)">
</quill-editor>
<input type="file" accept=".png,.jpg,.jpeg" @change="changePic" multiple id="quillPicUpload"
style="display: none" />
<input type="file" accept="video/*" @change="changeVideo" id="quillVideoUpload" style="display: none" />
<input type="file" @change="changeFile" id="quillFileUpload" style="display: none" />
</div>
</template>
<script>
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
import { quillEditor } from 'vue-quill-editor'
import http from "@/api/http";
import { updateimg } from "@/api/SpliceUrl/SpliceUrl";
export default {
components: {
quillEditor
},
data() {
return {
content: `<p>hello world</p>`,
editorOption: {
// 富文本编辑器配置
modules: {
//工具栏定义的
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线 -----['bold', 'italic', 'underline', 'strike']
['blockquote', 'code-block'], // 引用 代码块-----['blockquote', 'code-block']
[{ header: 1 }, { header: 2 }], // 1、2 级标题-----[{ header: 1 }, { header: 2 }]
[{ list: 'ordered' }, { list: 'bullet' }], // 有序、无序列表-----[{ list: 'ordered' }, { list: 'bullet' }]
[{ script: 'sub' }, { script: 'super' }], // 上标/下标-----[{ script: 'sub' }, { script: 'super' }]
[{ indent: '-1' }, { indent: '+1' }], // 缩进-----[{ indent: '-1' }, { indent: '+1' }]
[{ direction: 'rtl' }], // 文本方向-----[{'direction': 'rtl'}]
[{ size: ['12px', '100%', '16px', '18px', '20px', '22px', '24px', '28px', '32px', '48px'] }], // 字体大小-----[{ size: ['small', false, 'large', 'huge'] }]
[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题-----[{ header: [1, 2, 3, 4, 5, 6, false] }]
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色-----[{ color: [] }, { background: [] }]
[{ font: [] }], // 字体种类-----[{ font: [] }]
[{ align: [] }], // 对齐方式-----[{ align: [] }]
['clean'], // 清除文本格式-----['clean']
['image'] // 链接、图片、视频-----['link', 'image', 'video']
],
handlers: {
image: function (value) {
if (value) {
document.querySelector('#quillPicUpload').click() // 劫持原来的图片点击按钮事件
} else {
this.quill.format('image', false)
}
},
video: function (value) {
if (value) {
document.querySelector('#quillVideoUpload').click()
} else {
// return
this.quill.format('video', false)
}
},
// 文件上传
upload: value => {
if (value) {
document.querySelector('#quillFileUpload').click()
} else {
this.quill.format('upload', false)
}
}
}
}
},
//主题
theme: 'snow',
placeholder: '请输入正文'
}
}
},
created() {
this.content = this.editorContent
},
props: {
editorContent: {
type: String,
default: ''
}
},
methods: {
//失去焦点事件
onEditorBlur(quill) {
// console.log('editor blur!', quill)
},
//获得焦点事件
onEditorFocus(quill) {
// console.log('editor focus!', quill)
},
// 准备富文本编辑器
onEditorReady(quill) {
// console.log('editor ready!', quill)
},
//内容改变事件
onEditorChange({ quill, html, text }) {
// console.log('editor change!', quill, html, text)
this.content = html
this.$emit('change', { quill, html, text })
},
// 图片上传
changePic(e) {
let fileList = e.target.files
let formData = new FormData()
for (let i = 0; i < fileList.length; i++) {
formData.append('update_image', fileList[i])
}
http
.post(updateimg, formData)
.then(res => {
//console.log(res.data.update_image)
if (res.data.update_image) {
let picList = res.data.update_image
let quill = this.$refs.myQuillEditor.quill
let index = quill.getSelection().index // 光标位置
quill.insertEmbed(index, 'image', picList) // 插入图片 图片地址
// 调整光标到最后
quill.setSelection(index + 1) // 光标后移一位
} else {
this.$message({
message: '图片上传失败:',
type: 'error'
})
}
})
.catch(err => {
console.log(err)
})
},
// 上传视频
changeVideo(e) {
this.$message.warning('不支持上传视频')
},
// 上传文件
changeFile(e) { }
}
}
</script>
<style lang='scss'>
.vue-quill-editor-com {
line-height: normal !important;
// height: 500px;
min-height: 400px;
height: 400px;
}
.ql-editor {
height: 350px !important;
}
.ql-snow .ql-tooltip[data-mode='link']::before {
content: '请输入链接地址:';
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
border-right: 0px;
content: '保存';
padding-right: 0px;
}
.ql-snow .ql-tooltip[data-mode='video']::before {
content: '请输入视频地址:';
}
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
content: 'normal';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='12px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='12px']::before {
content: '12px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='16px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='16px']::before {
content: '16px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='18px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='18px']::before {
content: '18px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='20px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='20px']::before {
content: '20px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='22px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='22px']::before {
content: '22px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='24px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='24px']::before {
content: '24px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='28px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='28px']::before {
content: '28px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='32px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='32px']::before {
content: '32px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='48px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='48px']::before {
content: '48px';
}
.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: '等宽字体';
}
</style>
2.管粘贴的问题
拦截粘贴的图片并转换成文件上传到服务端
//配置项增加
//图片粘贴拦截
clipboard: {
// 粘贴板,处理粘贴图片 *** 主要是这里
matchers: [[Node.ELEMENT_NODE, this.stopimgclip]],
},
//方法
stopimgclip(node, Delta) {
let ops = []
Delta.ops.forEach(op => {
if (op.insert && typeof op.insert === 'string') {
ops.push({
insert: op.insert,
})
} else { //给出提醒
if (op.insert.image) {
//给个提示
this.$message({
message: '粘贴的内容是图片',
type: 'warning',
})
//调用方法
this.mybase64tofileandupload(op.insert.image)
// return
}
}
})
Delta.ops = ops
return Delta
},
stopimgclip(node, Delta) {
let ops = []
Delta.ops.forEach(op => {
if (op.insert && typeof op.insert === 'string') {
ops.push({
insert: op.insert,
})
} else { //给出提醒
if (op.insert.image) {
//给个提示
this.$message({
message: '粘贴的内容是图片',
type: 'warning',
})
//调用方法
this.mybase64tofileandupload(op.insert.image)
// return
}
}
})
Delta.ops = ops
return Delta
},
3. 一个页面渲染多个富文本编辑器(使用场景循环遍历 个数不定)
虽然可离谱但是业务的使用场景就是这个昨天百度了一些经验都是些的定死的没有符合我这种需求的 所以回去之后夜不能寐 在梦里一顿瞎想 有了个浅显的方案 还真别说今天来了之后一试验 还真的能用 感恩睡梦中的自己
我们在页面上使用不正常的原因无外乎就是有些用的是dom操作要拿确定的Id 和ref之类的去查 那我们到这里其实可以把他们变的不一样 把组件的ref 和标签的通过Props传进来的这种方式 就可以做到区分开了 大家各司其职 谁也不会发癫不正常了代码如下
//第一步改html 部分
<quill-editor v-model="content" :ref="quillref" :options="editorOption" @blur="onEditorBlur($event)"
@focus="onEditorFocus($event)" @change="onEditorChange($event)">
</quill-editor>
<input type="file" accept=".png,.jpg,.jpeg" @change="changePic" multiple :id="picupid" style="display: none" />
//第二步 props
quillref: {
type: String,
default: 'myQuillEditor'
},
picupid: {
type: String,
default: 'quillPicUpload'
},
//第三步 拦截方法那里改一下 不然拿不到当前环境的东西
image: (value)=> {
if (value) {
document.querySelector('#'+this.picupid).click() // 劫持原来的图片点击按钮事件
} else {
//this.quill
this.$refs[`${this.quillref}`].quill.format('image', false)
}
},
// 然后下面那种填东西的改一下
let quill = _that.$refs[`${_that.quillref}`].quill
// 使用的时候
<div v-for="item in 4" :key="item">
{{ item }}
<vueQuillEditor :picupid="'quillPicUpload'+item" :quillref="'myQuillEditor'+item" v-if="myquillshow" :editorContent="'1111'" @change="editorChange"></vueQuillEditor>
</div>