vue-quill-editor + + antd 組件封裝(包含圖片上傳)


QuillEditor 組件封裝:

需要 使用 npm 安裝依賴:

"vue-quill-editor": "^3.0.6",
"quill-image-resize-module": "^3.0.0",

QuillEditor .vue 代碼:

  1 <template>
  2   <div>
  3     <quill-editor
  4       class="editor"
  5       ref="myTextEditor"
  6       v-model="editorContent"
  7       :options="editorOption"
  8       @change="onEditorChange($event)"
  9       @ready="ready($event)"
 10     >
 11     </quill-editor>
 12     <a-upload
 13       class="ant-my-uploader"
 14       style="display:none"
 15       action="/content/file/upload-oss-image"
 16       :before-upload="beforeUpload"
 17       @change="handleChange"
 18     >
 19       <a-button> <a-icon type="upload" />Upload </a-button>
 20     </a-upload>
 21     <div>
 22       剩余可輸入
 23       <span :style="{ color: 5000 - innerText.length < 0 ? 'red' : 'black' }">{{
 24         5000 - innerText.length
 25       }}</span>
 26  27     </div>
 28   </div>
 29 </template>
 30 
 31 <script>
 32 import { quillEditor } from "vue-quill-editor";
 33 import "quill/dist/quill.core.css";
 34 import "quill/dist/quill.snow.css";
 35 import "quill/dist/quill.bubble.css";
 36 import Quill from "quill";
 37 import ImageResize from "quill-image-resize-module";
 38 Quill.register("modules/imageResize", ImageResize);
 39 // 自定義文字大小
 40 let fontSizeStyle = Quill.import("attributors/style/size");
 41 fontSizeStyle.whitelist = [
 42   "10px",
 43   "11px",
 44   "12px",
 45   "13px",
 46   "14px",
 47   "15px",
 48   "16px",
 49   "17px",
 50   "18px",
 51   "19px",
 52   "20px",
 53   "21px",
 54   "22px",
 55   "23px",
 56   "24px",
 57   "25px",
 58   "26px"
 59 ];
 60 Quill.register(fontSizeStyle, true);
 61 import { lineHeightStyle } from "@/utils/lineheight";
 62 //工具菜單欄配置
 63 const toolbarOptions = [
 64   ["bold", "italic", "underline", "strike"], // 加粗 斜體 下划線 刪除線
 65   ["blockquote", "code-block"], // 引用  代碼塊
 66   [{ header: 1 }, { header: 2 }], // 1、2 級標題
 67   [{ list: "ordered" }, { list: "bullet" }], // 有序、無序列表
 68   [{ script: "sub" }, { script: "super" }], // 上標/下標
 69   [{ indent: "-1" }, { indent: "+1" }], // 縮進
 70   // [{'direction': 'rtl'}],                         // 文本方向
 71   // [{ size: ["small", false, "large", "huge"] }], // 字體大小
 72   [{ size: fontSizeStyle.whitelist }], // 字體大小
 73   [{ header: [1, 2, 3, 4, 5, 6, false] }], // 標題
 74   [{ color: [] }, { background: [] }], // 字體顏色、字體背景顏色
 75   [{ font: [] }], // 字體種類
 76   [{ align: [] }], // 對齊方式
 77   [{ lineheight: ["initial", "1", "1.5", "1.75", "2", "3", "4", "5"] }], // 對齊方式
 78   ["clean"], // 清除文本格式
 79   ["link", "image", "video"] // 鏈接、圖片、視頻
 80 ];
 81 export default {
 82   components: {
 83     quillEditor
 84   },
 85   props: {
 86     content: String
 87   },
 88   data() {
 89     return {
 90       innerText: "",
 91       editorContent: null,
 92       editorOption: {
 93         placeholder: "請在這里輸入", //提示
 94         readyOnly: false, //是否只讀
 95         theme: "snow", //主題 snow/bubble
 96         syntax: true, //語法檢測
 97         modules: {
 98           imageResize: {
 99             //添加
100             displayStyles: {
101               //添加
102               backgroundColor: "black",
103               border: "none",
104               color: "white"
105             },
106             modules: ["Resize", "DisplaySize", "Toolbar"] //添加
107           },
108           toolbar: {
109             container: toolbarOptions,
110             handlers: {
111               image: function(value) {
112                 if (value) {
113                   console.log(value);
114                   // 觸發input框選擇圖片文件
115                   document.querySelector(".ant-my-uploader input").click();
116                 } else {
117                   this.quill.format("image", false);
118                 }
119               },
120               lineheight: function(value) {
121                 if (value) {
122                   this.quill.format("lineHeight", value);
123                 } else {
124                   console.log(value);
125                 }
126               }
127             }
128           }
129         }
130       },
131       loading: false
132     };
133   },
134   computed: {
135     editor() {
136       return this.$refs.myTextEditor.quillEditor;
137     }
138   },
139   mounted() {
140     // Quill.register({ "formats/line-height": LineHeight }, true);
141   },
142   watch: {
143     content: {
144       handler: function(val) {
145         this.editorContent = val;
146       },
147       immediate: true
148     }
149   },
150   methods: {
151     ready() {
152       Quill.register({ "formats/lineHeight": lineHeightStyle }, true);
153     },
154     onEditorChange(editor) {
155       // this.editorContent = editor.html;
156       this.innerText = editor.text.replace(/[\r\n]$/g, "");
157       this.$emit("onChange", {
158         content: editor.html,
159         textLength: this.innerText.length
160       });
161     },
162     // 上傳圖片
163     uploadSuccess(val) {
164       let quill = this.$refs.myTextEditor.quill;
165       // 獲取光標所在位置
166       let length = quill.getSelection().index;
167       // 插入圖片  res.url為服務器返回的圖片地址
168       quill.insertEmbed(length, "image", val);
169       // 調整光標到最后
170       quill.setSelection(length + 1);
171     },
172     handleChange(info) {
173       switch (info.file.status) {
174         case "uploading":
175           this.loading = true;
176           break;
177         case "done":
178           this.loading = false;
179           // eslint-disable-next-line no-case-declarations
180           const { response } = info.file; // 請求返回的數據
181           if (response.code == 200) {
182             this.uploadSuccess(response.data);
183             this.$message.success({
184               content: "上傳成功!",
185               key: "uploadPic",
186               duration: 2
187             });
188           } else {
189             this.$message.error({
190               content: response.msg || "上傳發生錯誤" + response.code,
191               key: "uploadPic",
192               duration: 2
193             });
194           }
195           break;
196         case "error":
197           this.loading = false;
198           // 錯誤消息提示
199           this.$message.error({
200             content: "網絡錯誤請稍后再試",
201             key: "uploadPic",
202             duration: 2
203           });
204           break;
205         default:
206           break;
207       }
208     },
209     beforeUpload(file) {
210       return new Promise((resolve, reject) => {
211         this.$message.success({
212           content: "上傳中",
213           key: "uploadPic",
214           duration: 2
215         });
216         const isJpgOrPng =
217           file.type === "image/jpeg" ||
218           file.type === "image/png" ||
219           file.type === "image/jpg";
220         if (!isJpgOrPng) {
221           this.$message.error("圖片僅支持 jpeg 或 png 或 jpg 格式");
222           return reject(false);
223         }
224         // const isLt300kb = file.size / 1024 < 300;
225         const isLt2M = file.size / 1024 / 1024 < 2;
226         if (!isLt2M) {
227           this.$message.error("圖片大於 2M");
228           return reject(false);
229         }
230         return resolve(true);
231       });
232     }
233   }
234 };
235 </script>
236 
237 <style>
238 .editor {
239   line-height: normal !important;
240   /* height: 400px; */
241   background-color: #ffffff;
242 }
243 .ql-snow .ql-tooltip[data-mode="link"]::before {
244   content: "請輸入鏈接地址:";
245 }
246 .ql-snow .ql-tooltip.ql-editing a.ql-action::after {
247   border-right: 0px;
248   content: "保存";
249   padding-right: 0px;
250 }
251 .ql-snow .ql-tooltip a.ql-action::after {
252   content: "編輯";
253 }
254 .ql-snow .ql-tooltip a.ql-remove::before {
255   content: "移除";
256 }
257 .ql-snow .ql-tooltip[data-mode="video"]::before {
258   content: "請輸入視頻地址:";
259 }
260 .ql-snow .ql-picker.ql-size .ql-picker-label::before,
261 .ql-snow .ql-picker.ql-size .ql-picker-item::before {
262   content: "14px";
263 }
264 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
265 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
266   content: "10px";
267 }
268 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
269 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
270   content: "18px";
271 }
272 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
273 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
274   content: "32px";
275 }
276 
277 .ql-snow .ql-picker.ql-header .ql-picker-label::before,
278 .ql-snow .ql-picker.ql-header .ql-picker-item::before {
279   content: "文本";
280 }
281 .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
282 .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
283   content: "標題1";
284 }
285 .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
286 .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
287   content: "標題2";
288 }
289 .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
290 .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
291   content: "標題3";
292 }
293 .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
294 .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
295   content: "標題4";
296 }
297 .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
298 .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
299   content: "標題5";
300 }
301 .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
302 .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
303   content: "標題6";
304 }
305 .ql-snow .ql-picker.ql-font .ql-picker-label::before,
306 .ql-snow .ql-picker.ql-font .ql-picker-item::before {
307   content: "標准字體";
308 }
309 .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
310 .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
311   content: "襯線字體";
312 }
313 .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
314 .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
315   content: "等寬字體";
316 }
317 /* 編輯器內部出現滾動條 */
318 .ql-container {
319   /* overflow-y: auto; */
320   height: 400px !important;
321 }
322 /*滾動條整體樣式*/
323 .ql-container ::-webkit-scrollbar {
324   width: 10px; /*豎向滾動條的寬度*/
325   height: 10px; /*橫向滾動條的高度*/
326 }
327 .ql-container ::-webkit-scrollbar-thumb {
328   /*滾動條里面的小方塊*/
329   background: #666666;
330   border-radius: 5px;
331 }
332 .ql-container ::-webkit-scrollbar-track {
333   /*滾動條軌道的樣式*/
334   background: #ccc;
335   border-radius: 5px;
336 }
337 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="10px"]::before,
338 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="10px"]::before {
339   content: "10px";
340 }
341 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="11px"]::before,
342 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="11px"]::before {
343   content: "11px";
344 }
345 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="12px"]::before,
346 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="12px"]::before {
347   content: "12px";
348 }
349 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="13px"]::before,
350 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="13px"]::before {
351   content: "13px";
352 }
353 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="14px"]::before,
354 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="14px"]::before {
355   content: "14px";
356 }
357 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="15px"]::before,
358 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="15px"]::before {
359   content: "15px";
360 }
361 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="16px"]::before,
362 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="16px"]::before {
363   content: "16px";
364 }
365 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="17px"]::before,
366 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="17px"]::before {
367   content: "17px";
368 }
369 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="18px"]::before,
370 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="18px"]::before {
371   content: "18px";
372 }
373 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="19px"]::before,
374 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="19px"]::before {
375   content: "19px";
376 }
377 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="20px"]::before,
378 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="20px"]::before {
379   content: "20px";
380 }
381 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="21px"]::before,
382 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="21px"]::before {
383   content: "21px";
384 }
385 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="22px"]::before,
386 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="22px"]::before {
387   content: "22px";
388 }
389 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="23px"]::before,
390 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="23px"]::before {
391   content: "23px";
392 }
393 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="24px"]::before,
394 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="24px"]::before {
395   content: "24px";
396 }
397 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="25px"]::before,
398 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="25px"]::before {
399   content: "25px";
400 }
401 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="26px"]::before,
402 .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="26px"]::before {
403   content: "26px";
404 }
405 .ql-snow .ql-picker.ql-lineheight .ql-picker-label::before{
406   content: "行高";
407 }
408 .ql-snow
409   .ql-picker.ql-lineheight
410   .ql-picker-item[data-value="initial"]::before {
411   content: "默認";
412 }
413 .ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value="1"]::before {
414   content: "1";
415 }
416 .ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value="1.5"]::before {
417   content: "1.5";
418 }
419 .ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value="1.75"]::before {
420   content: "1.75";
421 }
422 .ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value="2"]::before {
423   content: "2";
424 }
425 .ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value="3"]::before {
426   content: "3";
427 }
428 .ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value="4"]::before {
429   content: "4";
430 }
431 .ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value="5"]::before {
432   content: "5";
433 }
434 .ql-snow .ql-picker.ql-lineheight {
435   width: 70px;
436 }
437 </style>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM