VUE——基於Element、quillEditor和VueCropper的富文字圖片剪下上傳
阿新 • • 發佈:2018-12-25
我們要實現的功能如下:
步驟一、上傳圖片
步驟二、剪下圖片
步驟三、生成新圖片
安裝元件:我使用Yarn
yarn add vue-quill-editor quill vue-cropper
或者使用npm
npm install -d vue-quill-editor quill vue-cropper
element元件請自行下載並引入
實現程式碼如下:
第一部分:綜合元件部分,本檔案放置餘conponent資料夾下,名為textEditor.vue:
<template> <div> <!-- 圖片上傳元件--> <el-upload accept="image/*" action="192.168.0.108/api/subject/file/upload" class="avatar-uploader" name="upload" :show-file-list="false" :before-upload="beforeUpload"> <el-button size="small" type="primary">點選上傳圖片 到 文字編輯器</el-button> </el-upload> <!-- 編輯器元件--> <quill-editor class="editor" v-model="content" ref="myQuillEditor" :options="editorOption" @change="onEditorChange($event)"> </quill-editor> <!-- 圖片裁剪元件--> <el-dialog top="5vh" :visible.sync="isShowCropper"> <VueCropper style="height:600px;margin:20px 0" ref="cropper" :img="option.img" :outputSize="option.outputSize" :outputType="option.outputType" :info="option.info" :canScale="option.canScale" :autoCrop="option.autoCrop" :autoCropWidth="option.autoCropWidth" :autoCropHeight="option.autoCropHeight" :fixed="option.fixed" :fixedNumber="option.fixedNumber" > </VueCropper> <br/> <el-button type="primary" @click="onCubeImg()">生成圖片</el-button> <el-button @click="isShowCropper = false">取消</el-button> </el-dialog> </div> </template> <script> // 富文字工具欄配置 const toolbarOptions = [ ["bold", "italic", "underline", "strike"], // 加粗 斜體 下劃線 刪除線 ["blockquote", "code-block"], // 引用 程式碼塊 [{ header: 1 }, { header: 2 }], // 1、2 級標題 [{ list: "ordered" }, { list: "bullet" }], // 有序、無序列表 [{ script: "sub" }, { script: "super" }], // 上標/下標 [{ indent: "-1" }, { indent: "+1" }], // 縮排 // [{'direction': 'rtl'}], // 文字方向 [{ size: ["small", false, "large", "huge"] }], // 字型大小 [{ header: [1, 2, 3, 4, 5, 6, false] }], // 標題 [{ color: [] }, { background: [] }], // 字型顏色、字型背景顏色 [{ font: [] }], // 字型種類 [{ align: [] }], // 對齊方式 ["clean"], // 清除文字格式 ["link", "image", "video"] // 連結、圖片、視訊 ]; import { quillEditor } from "vue-quill-editor"; import { VueCropper } from "vue-cropper"; import { ApiUploadFile } from '../api'; import "quill/dist/quill.core.css"; import "quill/dist/quill.snow.css"; import "quill/dist/quill.bubble.css"; export default { name: 'textEditor', components: { quillEditor, VueCropper }, props: { /*編輯器的內容*/ value: { type: String }, /*圖片大小*/ maxSize: { type: Number, default: 4000 //kb } }, data() { return { // 富文字資料 content: this.value, quillUpdateImg: false, // 根據圖片上傳狀態來確定是否顯示loading動畫,剛開始是false,不顯示 editorOption: { placeholder: "", theme: "snow", // or 'bubble' placeholder: "請輸入您想輸入的內容", modules: { toolbar: { container: toolbarOptions, // container: "#toolbar", handlers: { image: function(value) { console.log(value) if (value) { // 觸發input框選擇圖片檔案 document.querySelector(".avatar-uploader input").click(); } else { this.quill.format("image", false); } }, } } } }, // 切圖器資料 option: { img: '', // 裁剪圖片的地址 info: true, // 裁剪框的大小資訊 outputSize: 1, // 裁剪生成圖片的質量 outputType: 'png', // 裁剪生成圖片的格式 canScale: false, // 圖片是否允許滾輪縮放 autoCrop: true, // 是否預設生成截圖框 autoCropWidth: 150, // 預設生成截圖框寬度 autoCropHeight: 150, // 預設生成截圖框高度 fixed: false, // 是否開啟截圖框寬高固定比例 fixedNumber: [4, 4], // 截圖框的寬高比例 }, isShowCropper: false, }; }, methods: { // 上傳切圖前呼叫 beforeUpload(file) { this.option.img = URL.createObjectURL(file); this.option.autoCropWidth = this.width; this.option.autoCropHeight = this.height; this.isShowCropper = true; return false; }, // 確定裁剪圖片 onCubeImg() { // 獲取cropper的截圖的base64 資料 this.$refs.cropper.getCropData(data => { this.isShowCropper = false // 先將顯示圖片地址清空,防止重複顯示 this.option.img = '' // 將剪裁後base64的圖片轉化為file格式 let file = this.convertBase64UrlToBlob(data) file.name = 'img' + new Date().getTime(); // 將剪裁後的圖片執行上傳 var fd = new FormData(); fd.append("file", file); this.$message.success("圖片正在上傳"); ApiUploadFile(fd).then(res => { // 獲取富文字元件例項 this.$message.success("圖片上傳成功"); let quill = this.$refs.myQuillEditor.quill; // loading動畫消失 this.quillUpdateImg = false; // 如果上傳成功 if (res.data.code == 0) { // 獲取游標所在位置 if (quill.getSelection()&&quill.getSelection().index) { let length = quill.getSelection().index; }else{ let length = 0; } // 插入圖片 res.url為伺服器返回的圖片地址 console.log(res) quill.insertEmbed(length, "image", res.data.data.imageUrl); // 調整游標到最後 quill.setSelection(length + 1); } else { this.$message.error("圖片插入失敗"); } }) }) }, // 將base64的圖片轉換為file檔案 convertBase64UrlToBlob(urlData) { let bytes = window.atob(urlData.split(',')[1]);//去掉url的頭,並轉換為byte //處理異常,將ascii碼小於0的轉換為大於0 let ab = new ArrayBuffer(bytes.length); let ia = new Uint8Array(ab); for (var i = 0; i < bytes.length; i++) { ia[i] = bytes.charCodeAt(i); } return new Blob([ab], { type: 'image/png' }); }, onEditorChange() { //富文字內容改變事件 this.$emit("input", this.content); }, } }; </script> <style> .avatar { width: 80%; height: 80%; } .editor { line-height: normal !important; height: 500px; margin-top: 10px; } .editor img { width: 200px; } .ql-toolbar.ql-snow .ql-formats { margin-right: 1px; } .ql-video { display: none !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: '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: '等寬字型'; } </style>
第二部分:呼叫程式碼,本檔案放置於page目錄的子資料夾下
<template> <div class="inputwrapper"> <el-form :model="formData" ref="formData" label-width="100px" class="demo-ruleForm"> <el-form-item style="width: 900px" label="標題" prop="title" :rules="[ { required: true, message: '標題不能為空'} ]" > <el-input type="text" v-model="formData.title" autocomplete="off"></el-input> </el-form-item> <el-form-item style="width: 900px" label="詳情" prop="detail" :rules="[ { required: true, message: '詳情不能為空'} ]" > <el-input type="text" v-model="formData.detail" autocomplete="off"></el-input> </el-form-item> <el-form-item label="編輯器" style="width: 900px" > <textEditor v-model="formData.content"/> </el-form-item> <el-form-item style="margin-top: 90px"> <el-button type="primary" @click="submitForm('formData')">提交</el-button> <el-button @click="resetForm('formData')">重置</el-button> </el-form-item> </el-form> </div> </template> <script> import textEditor from '../../components/textEditor.vue'; export default { components: { textEditor }, data() { return { formData: { title: '', detail: '', content: '', }, }; }, methods: { submitForm(formName) { this.$refs[formName].validate((valid) => { if (valid) { console.log(this.formData) } else { console.log('error submit!!'); return false; } }); }, resetForm(formName) { this.$refs[formName].resetFields(); } }, } </script>
以上為所有程式碼,歡迎朋友們使用。
參考文章:https://www.jianshu.com/p/21dab85b7fa8。歡迎指正。