当前位置:网站首页>The quill editor image zooms, multiple rich text boxes are used on one page, and the quill editor upload image address is the server address
The quill editor image zooms, multiple rich text boxes are used on one page, and the quill editor upload image address is the server address
2022-04-23 12:53:00 【ZMJ_ QQ】
quill Official documents Quickstart - Quill Rich Text Editor
Chinese version document Preface · Quill Official Chinese documents · Look at the clouds
Originally used directly quill-editor Rich text , But uploading pictures base64 The encoding length is too long , It needs to be converted into a server url Address , And a page needs to use multiple rich text boxes
Post two reference documents
stay vue3.0 in , Use quill-editor Picture drag and zoom function - Ice morning dew - Blog Garden
Complete code
1、 Installation dependency
npm install vue-quill-editor
npm install quill
npm install quill-image-drop-module
npm install quill-image-resize-module
2、 stay main.js Introduction in
// Rich text
// introduce quill-editor Editor
import VueQuillEditor from 'vue-quill-editor'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
Vue.use(VueQuillEditor);
// Realization quill-editor Drag and drop the editor to upload pictures
import * as Quill from 'quill'
import { ImageDrop } from 'quill-image-drop-module'
Quill.register('modules/imageDrop', ImageDrop)
// Realization quill-editor The editor resizes the picture
import ImageResize from 'quill-image-resize-module'
Quill.register('modules/imageResize', ImageResize)
3、 Package components editor.vue
If an error is reported when using multiple rich text boxes to upload pictures on a page TypeError: Cannot read property ‘index‘ of null, It's because quill-editor Of ref The value is written dead
Core code
1、 Of rich text components ref value
2、 The method to trigger the image upload must obtain the image corresponding to the rich text in the current page input, Just because the code is wrong , Each uploaded image is inserted into the first rich text box , It took four hours to find out that the method to trigger the upload was not written correctly ┭┮﹏┭┮
3、 Get rich text objects dynamically
4、 Empty after the picture is uploaded successfully input Value , Can solve input Can't upload duplicate files
Complete code
<template>
<div>
<input
type="file"
name="img"
accept="image/jpeg,image/jpg,image/png"
id="quillInput"
class="quill-img"
multiple="multiple"
hidden
@change="getImgUrl($event)"
/>
<quill-editor
class="editor"
:ref="toref"
v-model="content"
:options="editorOption"
@change="onEditorChange(toref)"
@blur="onEditorBlur($event, toref)"
@focus="onEditorFocus($event, toref)"
>
</quill-editor>
</div>
</template>
<script>
import { singleFile, multipleFiles } from "@/api/file";
import { mapGetters } from "vuex";
export default {
name: 'Editor',
props: {
/* The content of the editor */
value: {
type: String
},
/* input Input box Indexes */
quillIndex: {
type: Number,
default: 0
},
/* quill-editor Of ref value */
toref: {
type: String,
default: "quillEditor"
},
toplaceholder: {
type: String,
default: " Please enter ..."
}
},
data() {
return {
content: this.value,
editorOption: {
modules: {
imageDrop: true,
imageResize: {
displayStyles: {
backgroundColor: "black",
border: "none",
color: "white"
},
// modules: ["Resize", "DisplaySize", "Toolbar"]
},
toolbar: {
container: [
["bold", "italic", "underline", "strike"], // In bold Italics Underline Delete line
["blockquote", "code-block"], // quote Code block
[{ header: 1 }, { header: 2 }], // 1、2 Level title
[{ list: "ordered" }, { list: "bullet" }], // Orderly 、 Unordered list
[{ script: "sub" }, { script: "super" }], // Superscript / Subscript
[{ indent: "-1" }, { indent: "+1" }], // Indent
// [{'direction': 'rtl'}], // The text direction
[{ size: ["small", false, "large", "huge"] }], // font size
[{ header: [1, 2, 3, 4, 5, 6, false] }], // title
[{ color: [] }, { background: [] }], // The font color 、 Font background color
[{ font: [] }], // Font type
[{ align: [] }], // Alignment mode
["clean"], // Clear text formatting
["image"], // link 、 picture 、 video
],// Tools menu bar configuration
handlers: {
'image': (value) => {
if (value) {
// upload Click to upload the event
let index = this.quillIndex;
document.querySelectorAll(".quill-img")[index].click();
//document.queryselector("#quillInput").click();
}
}
},
}
},
placeholder: this.toplaceholder, // Tips
readyOnly: false, // Is it read-only
theme: "snow", // The theme snow/bubble
syntax: true, // Syntax checking
},
}
},
computed: {
...mapGetters([
"HOST"
]),
},
watch: {
value() {
this.content = this.value;
},
},
methods: {
// Focus on events Deleting
onEditorFocus(e, ref) {
console.log("foucus", e, ref)
},
// Defocus event Deleting
onEditorBlur(e, ref) {
console.log("blur", ref)
},
onEditorChange(toref) {
// Trigger parent Change the value of the parent component
this.$emit("input", this.content, toref);
},
// Upload pictures in the overview of failure mechanism
getImgUrl(e) {
e.stopPropagation();
if (e.target.files.length > 0) {
this.getMultipleUrl(e.target.files); // Multiple file upload
}
},
getMultipleUrl(file) {
// Multiple file upload
var formData = new FormData();
file.forEach(element => {
formData.append("file", element);
});
multipleFiles(formData).then((res) => {
let quill = this.$refs[this.toref].quill;// Solve the above refs Report errors
if (res.data.code == 20000) {
let list = res.data.data;
list.forEach(element => {
let url = this.HOST + element.afterName; // Splice picture address
// Get the cursor position
let length = quill.selection.savedRange.index;
// Insert a picture res.url The image address returned for the server
quill.insertEmbed(length, "image", url);
// Adjust the cursor to the end
quill.setSelection(length + 1);
});
} else {
this.$message.error(" Picture upload failed !")
}
}).finally(() => {
// Clear the of the input box value, solve input Can't upload duplicate files
let index = this.quillIndex;
document.querySelectorAll(".quill-img")[index].value = null;
});
},
}
}
</script>
<style lang="scss" scoped>
/* Rich text editor Modify height */
.editor {
line-height: normal !important;
margin-bottom: 0;
}
.editor ::v-deep .ql-container {
min-height: 200px !important;
}
</style>
<style>
/* Revised to Chinese */
.ql-snow .ql-tooltip[data-mode="link"]::before {
content: " Please enter the link address :";
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
border-right: 0px;
content: " preservation ";
padding-right: 0px;
}
.ql-snow .ql-tooltip[data-mode="video"]::before {
content: " Please enter the video address :";
}
.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: " Text ";
}
.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: " title 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: " title 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: " title 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: " title 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: " title 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: " title 6";
}
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
content: " Standard font ";
}
.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: " Serif font ";
}
.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: " Equal width font ";
}
</style>
4、 Introduce... In the parent component
1、toref The value of should be unique and not repeated ,quillIndex The value of should be the same as that of the rich text component class Same order
2、 Update the value of the parent component
changeEditor(data, model) { // Subcomponents toref Value and v-model The bound values are the same this.qualityList[model] = data; }
Use multiple rich text boxes in the parent component
<editor
v-if="edit"
toref="qualityAppraisalPlan"
:quillIndex="0"
v-model="qualityList.qualityAppraisalPlan"
@input="changeEditor"
/>
<div
v-if="!edit"
class="ql-editor"
v-html="qualityList.qualityAppraisalPlan"
></div>
<p> One 、 Appraisal object </p>
<editor
v-if="edit"
toref="identificationObject"
:quillIndex="1"
v-model="qualityList.identificationObject"
toplaceholder=" Please enter the identification object ..."
@input="changeEditor"
/>
<div
style="padding-left: 20px"
v-if="!edit"
class="ql-editor"
v-html="qualityList.identificationObject"
></div>
Screenshot of the page

版权声明
本文为[ZMJ_ QQ]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204230616457199.html
边栏推荐
- I changed to a programmer at the age of 31. Now I'm 34. Let me talk about my experience and some feelings
- Everything can be expected in the future | one 2022 campus recruitment officially opened
- Kubernetes 入门教程
- A graphic designer's fantasy world | ones characters
- Servlet监听器&过滤器介绍
- Buuctf Web [gxyctf2019] no dolls
- 力扣刷题之完全二叉树的节点个数
- Sort out several uses of network IP agent
- Fashion cloud learning - input attribute summary
- 没有空闲服务器?导入 OVF 镜像快速体验 SmartX 超融合社区版
猜你喜欢
随机推荐
风尚云网学习-h5的input:type属性的image属性
STM32 control stepper motor (ULN2003 + 28byj)
4. DRF permission & access frequency & filtering & sorting
Buuctf Web [gxyctf2019] no dolls
The continuous construction of the Internet industry platform is not only able to collect traffic
Image attribute of input: type attribute of fashion cloud learning -h5
leetcode-791. Custom string sorting
uni-app 原生APP-本地打包集成极光推送(JG-JPUSH)详细教程
Customize the shortcut options in El date picker, and dynamically set the disabled date
C, calculation code of parameter points of two-dimensional Bezier curve
Luogu p5540 [balkanoi2011] timeismoney | minimum product spanning tree problem solution
Wonderful review | the sixth issue of "source" - open source economy and industrial investment
Ad20 supplementary note 3 - shortcut key + continuous update
box-sizing
CVPR 2022&NTIRE 2022|首个用于高光谱图像重建的 Transformer
将新增和编辑的数据同步更新到列表
BUUCTF WEB [BJDCTF2020]The mystery of ip
天梯赛赛前练习
leetcode-791. 自定义字符串排序
STM32控制步进电机(ULN2003+28byj)














