当前位置:网站首页>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
边栏推荐
- MySQL function - recursive function
- Wonderful review | the sixth issue of "source" - open source economy and industrial investment
- A graphic designer's fantasy world | ones characters
- [vulnhub range] - DC2
- 风尚云网学习-h5的input:type属性的image属性
- SSM framework series - JUnit unit test optimization day2-3
- 21 天学习MongoDB笔记
- If you were a golang interviewer, what questions would you ask?
- 力扣刷题之完全二叉树的节点个数
- Object. The disorder of key value array after keys
猜你喜欢
Packet capturing and sorting -- TCP protocol [8]
No idle servers? Import OVF image to quickly experience smartx super fusion community version
A graphic designer's fantasy world | ones characters
【蓝桥杯】4月17日省赛刷题训练(前3道题)
Synchronously update the newly added and edited data to the list
Softbank vision fund entered the Web3 security industry and led a new round of investment of US $60 million in certik
0基础可以考CPDA数据分析师证书吗
A graphic designer's fantasy world | ones characters
SSM框架系列——Junit单元测试优化day2-3
梳理网络IP代理的几大用途
随机推荐
How does sqlserver insert or update the number of weeks of the day instead of text
Buuctf Web [gxyctf2019] no dolls
【unity笔记】L4Unity中的基础光照
Web17——EL与JSTL的使用
box-sizing
Please help me see what this is, mysql5 5. Thanks
Introduction to kubernetes
5 free audio material websites, recommended collection
梳理网络IP代理的几大用途
Softbank vision fund entered the Web3 security industry and led a new round of investment of US $60 million in certik
Flash project cross domain interception and DBM database learning [Baotou cultural and creative website development]
Kubernetes 入門教程
Everything can be expected in the future | one 2022 campus recruitment officially opened
没有空闲服务器?导入 OVF 镜像快速体验 SmartX 超融合社区版
Unable to create servlet under SRC subfile of idea
天梯赛赛前练习
风尚云网学习-input属性总结
SSM框架系列——Junit单元测试优化day2-3
At instruction of nbiot
31. 下一个排列