vue實(shí)現(xiàn)圖片裁剪后上傳
本文實(shí)例為大家分享了vue實(shí)現(xiàn)圖片裁剪后上傳的具體代碼,供大家參考,具體內(nèi)容如下
一、背景
目前負(fù)責(zé)的系統(tǒng)(商城后臺(tái)管理系統(tǒng))里面有這么一個(gè)需求,為了配合前臺(tái)的展示,上傳的商品圖片比較必須是1:1的正方形。(其它地方有時(shí)會(huì)有5:4或者16:9的需求,但較少)。所以需要對(duì)上傳的圖片先進(jìn)行裁剪,并且按要求只能裁剪為1:1,然后在進(jìn)行上傳。
當(dāng)然,為了兼容系統(tǒng)其它地方有5:4或者16:9的圖片比例需求,需要給出一個(gè)參數(shù),可以隨時(shí)控制圖片裁剪的比例。
二、使用什么插件實(shí)現(xiàn)
使用 vue-cropper 顯示,該插件是基于 cropper 的二次封裝,簡(jiǎn)單小巧,更合適vue項(xiàng)目。注意:功能沒有 cropper 強(qiáng)大。
三、使用 cropper
3.1 封裝一下cropper, 配置自己想要的參數(shù)
<template> <div class="Cropper"> <el-dialog :visible.sync="dialogVisible" width="740px" title="圖片裁剪" :before-close="handleClose" :close-on-click-modal="false"> <div class="cropper-container"> <div class="cropper-el"> <vue-cropper ref="cropper" :img="cropperImg" :output-size="option.size" :output-type="option.outputType" :info="true" :can-move="option.canMove" :can-move-box="option.canMoveBox" :fixed-box="option.fixedBox" :auto-crop="option.autoCrop" :auto-crop-width="option.autoCropWidth" :auto-crop-height="option.autoCropHeight" :center-box="option.centerBox" :high="option.high" :info-true="option.infoTrue" @realTime="realTime" :enlarge="option.enlarge" :fixed="option.fixed" :fixed-number="option.fixedNumber" :limitMinSize="option.limitMinSize" /> </div> <!-- 預(yù)覽 ==>> 我不需要預(yù)覽 --> <!-- <div class="prive-el"> <strong>預(yù)覽:</strong> <div class="prive-style" :style="{'width': '200px', 'height': '200px', 'overflow': 'hidden', 'margin': '10px 25px', 'display':'flex', 'align-items' : 'center'}"> <div class="prive-style" :style="{'width': previews.w + 'px', 'height': previews.h + 'px', 'overflow': 'hidden', 'margin': '10px 25px', 'display':'flex', 'align-items' : 'center'}"> <div class="preview" :style="previews.div"> <img :src="previews.url" :style="previews.img"> </div> </div> <el-button @click="uploadBth">重新上傳</el-button> </div> --> </div> <span slot="footer" class="dialog-footer"> <el-button @click="uploadBth">重新上傳</el-button> <el-button @click="handleClose">取 消</el-button> <el-button type="primary" @click="saveImg">確 定</el-button> </span> </el-dialog> </div> </template> <script> import { VueCropper } from 'vue-cropper'; export default { name: 'Cropper', components: { VueCropper }, props: { dialogVisible: { type: Boolean, default: false }, imgType: { type: String, default: 'blob' }, cropperImg: { type: String, default: '' }, zoomScale: { // 裁剪比例,默認(rèn)1:1 type: Array, default: [1, 1] } }, data () { return { previews: {}, option: { img: '', // 裁剪圖片的地址 size: 1, // 裁剪生成圖片的質(zhì)量 outputType: 'png', // 裁剪生成圖片的格式 默認(rèn)jpg canMove: false, // 上傳圖片是否可以移動(dòng) fixedBox: false, // 固定截圖框大小 不允許改變 canMoveBox: true, // 截圖框能否拖動(dòng) autoCrop: true, // 是否默認(rèn)生成截圖框 // 只有自動(dòng)截圖開啟 寬度高度才生效 autoCropWidth: 500, // 默認(rèn)生成截圖框?qū)挾? autoCropHeight: 500, // 默認(rèn)生成截圖框高度 centerBox: true, // 截圖框是否被限制在圖片里面 high: false, // 是否按照設(shè)備的dpr 輸出等比例圖片 enlarge: 1, // 圖片根據(jù)截圖框輸出比例倍數(shù) mode: 'contain', // 圖片默認(rèn)渲染方式 maxImgSize: 2000, // 限制圖片最大寬度和高度 // limitMinSize: [500,500], // 更新裁剪框最小屬性 limitMinSize: 500, // 更新裁剪框最小屬性 infoTrue: true, // true 為展示真實(shí)輸出圖片寬高 false 展示看到的截圖框?qū)捀? fixed: true, // 是否開啟截圖框?qū)捀吖潭ū壤?(默認(rèn):true) // fixedNumber: [1, 1] // 截圖框的寬高比例 ==>> 這個(gè)參數(shù)目前沒有作用(作者解釋的) fixedNumber: this.zoomScale // 截圖框的寬高比例 }, }; }, methods: { // 裁剪時(shí)觸發(fā)的方法,用于實(shí)時(shí)預(yù)覽 realTime (data) { this.previews = data; }, // 重新上傳 uploadBth () { this.$emit('update-cropper'); }, // 取消關(guān)閉彈框 handleClose () { this.$emit('colse-dialog', false); }, // 獲取裁剪之后的圖片,默認(rèn)blob,也可以獲取base64的圖片 saveImg () { if (this.imgType === 'blob') { this.$refs.cropper.getCropBlob(data => { this.$emit('upload-img', data); }); } else { this.$refs.cropper.getCropData(data => { this.uploadFile = data; this.$emit('upload-img', data); }); } } } }; </script> <style lang="scss" scoped> .Cropper { .cropper-el { height: 700px; width: 700px; flex-shrink: 0; } .cropper-container { display: flex; justify-content: space-between; .prive-el { flex: 1; align-self: center; text-align: center; .prive-style { margin: 0 auto; flex: 1; -webkit-flex: 1; display: flex; display: -webkit-flex; justify-content: center; -webkit-justify-content: center; overflow: hidden; background: #ededed; margin-left: 40px; } .preview { overflow: hidden; } .el-button { margin-top: 20px; } } } } </style> <style lang="scss"> .cropper-box-canvas img{ width: 100% !important; height: 100% !important; } </style>
3.2 將 el-upload 和 cropper 組合,封裝,其他地方可以直接調(diào)用
<template> <div> <!-- 注意:必須關(guān)閉自動(dòng)上傳屬性 auto-upload --> <el-upload :http-request="Upload" :multiple="true" list-type="picture-card" :file-list="productImageList" :on-remove="removeImage" :limit="12" :before-upload="beforeAvatarUpload" ref="fileUpload" :auto-upload="false" :on-change="selectChange" action="" class="cropper-upload-box" > <i slot="default" class="el-icon-plus"></i> </el-upload> <cropper v-if="showCropper" :dialog-visible="showCropper" :cropper-img="cropperImg" :zoomScale="zoomScale" @update-cropper="updateCropper" @colse-dialog="closeDialog" @upload-img="uploadImg" /> </div> </template> <script> import Cropper from "@/components/cropper"; import { client, randomWord } from '@/utils/alioss' export default { name: "CropperUpload", data() { return { productImageList: [], showCropper: false, // 是否顯示裁剪框 cropperImg: "" // 需要裁剪的圖片 }; }, props: { defaultImgList: { // 默認(rèn)顯示的圖片列表 type: Array, default: () => [] }, zoomScale: { // 裁剪比例,默認(rèn)1:1 type: Array, default: [1, 1] } }, components: { Cropper }, watch: { defaultImgList: { handler: function(newVal, oldVal){ this.productImageList = newVal // 賦值 }, deep: true } }, methods: { beforeAvatarUpload(file) { const isLt2M = file.size / 1024 / 1024 < 2; // 原圖片 // const isLt2M = this.uploadFile.size / 1024 / 1024 < 1; //裁剪后的圖片(會(huì)比原圖片大很多,應(yīng)該是轉(zhuǎn)成Blob的原因?qū)е拢? if (!isLt2M) { this.$message.error("上傳圖片大小不能超過 2MB!"); this.noCanUpload = true // 如果這里被攔截,將自動(dòng)刪除不能上傳的圖片 return false } // return isLt2M }, removeImage(file, fileList) { const index = this.productImageList.findIndex(item => { return item.uid == file.uid; }); if (index > -1) { this.productImageList.splice(index, 1); } this.$emit('getUploadImg', this.productImageList) // 把最新上傳的圖片列表返回 }, Upload(file) { var fileName = `img/${randomWord( true, 20 )}${+new Date()}${file.file.name.substr(file.file.name.indexOf("."))}`; // client().put(fileName, file.file).then(result => { client() .put(fileName, this.uploadFile) .then(result => { // 上傳裁剪后的圖片 console.log(result); this.productImageList.push({ url: result.url, uid: file.file.uid, saveUrl: "/" + result.name }); this.showCropper = false; this.$emit('getUploadImg', this.productImageList) // 把最新上傳的圖片列表返回 }) .catch(err => { this.showCropper = false; console.log(err); }); }, // 更新圖片 updateCropper() { if(!this.noCanUpload){ let fileList = this.$refs.fileUpload.uploadFiles // 獲取文件列表 let index02 = fileList.findIndex(item => { // 把取消裁剪的圖片刪除 return item.uid == this.currentFile.uid; }); fileList.splice(index02, 1) } let index = this.$refs.fileUpload.$children.length - 1; this.$refs.fileUpload.$children[index].$el.click(); }, // 關(guān)閉窗口 closeDialog() { this.showCropper = false; if(!this.noCanUpload){ let fileList = this.$refs.fileUpload.uploadFiles // 獲取文件列表 let index = fileList.findIndex(item => { // 把取消裁剪的圖片刪除 return item.uid == this.currentFile.uid; }); fileList.splice(index, 1) } }, // 上傳圖片 uploadImg(file) { this.uploadFile = file; // this.$refs.fileUpload.submit(); // 判斷裁剪后圖片的寬高 let img = new Image() img.src = window.URL.createObjectURL(file); // Blob轉(zhuǎn)成url 才能給img顯示 img.onload = () => { let minProp = Math.min(img.width, img.height) //裁剪后的圖片寬,高 ==> 取最小值 if( minProp < 500){ // 如果最小值比設(shè)置的最小值(默認(rèn)為500)小 this.$message.error(`請(qǐng)保證圖片短邊最小為500`); return false } this.$refs.fileUpload.submit(); } }, selectChange(file) { this.noCanUpload = false let files = file.raw; var reader = new FileReader(); reader.onload = e => { let data; if (typeof e.target.result === "object") { // 把Array Buffer轉(zhuǎn)化為blob 如果是base64不需要 data = window.URL.createObjectURL(new Blob([e.target.result])); } else { data = e.target.result; } this.cropperImg = data; // 圖片圖片尺寸,如果是正方形,則直接上傳;否則調(diào)用裁剪 let img = new Image() img.src = this.cropperImg; img.onload = () => { if(img.width == img.height){ // 本來就是正方形 => 直接上傳 this.uploadFile = files; this.$refs.fileUpload.submit(); // 調(diào)用上傳方法 }else{ this.showCropper = true; // 不是正方形的圖片才開啟裁剪 this.currentFile = file // 保存當(dāng)前操作裁剪的圖片 } } }; // 轉(zhuǎn)化為base64 // reader.readAsDataURL(file) // 轉(zhuǎn)化為blob reader.readAsArrayBuffer(files); // this.showCropper = true; // 默認(rèn)開啟裁剪 } } }; </script> <style lang="scss"> .cropper-upload-box{ display: flex; .el-upload{ width: 148px; height: 148px; } } </style>
3.3 其他頁面中調(diào)用裁剪組件
<!-- zoomScale:定義的裁剪比例; defaultImgList: 默認(rèn)顯示的圖片列表 @getUploadImg:這個(gè)事件將得到更新后(上傳、刪除)的圖片列表,在頁面中重新賦值給默認(rèn)的列表變量后就可以做頁面中的邏輯處理了 --> <cropper-upload :zoomScale='[1,1]' :defaultImgList="productImageList" @getUploadImg="getUploadImg"></cropper-upload>
自此,圖片裁剪功能實(shí)現(xiàn)?。。?/p>
3.4 看一下頁面中的效果
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vue+element-ui+sortable.js實(shí)現(xiàn)表格拖拽功能
這篇文章主要為大家詳細(xì)介紹了vue+element-ui+sortable.js實(shí)現(xiàn)表格拖拽功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04vue中響應(yīng)式布局如何將字體大小改成自適應(yīng)
這篇文章主要介紹了vue中響應(yīng)式布局如何將字體大小改成自適應(yīng),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09vue對(duì)storejs獲取的數(shù)據(jù)進(jìn)行處理時(shí)遇到的幾種問題小結(jié)
這篇文章主要介紹了vue對(duì)storejs獲取的數(shù)據(jù)進(jìn)行處理時(shí)遇到的幾種問題小結(jié),需要的朋友可以參考下2018-03-03Vue3?TypeScript?實(shí)現(xiàn)useRequest詳情
本文介紹了Vue3?TypeScript實(shí)現(xiàn)useRequest詳情,useRequest可能是目前社區(qū)中最強(qiáng)大,最接地氣的請(qǐng)求類?Hooks了??梢愿采w99%的網(wǎng)絡(luò)請(qǐng)求場(chǎng)景,無論是讀還是寫,無論是普通請(qǐng)求還是分頁請(qǐng)求,無論是緩存還是防抖節(jié)流,通通都能支持,關(guān)于其介紹需要的小伙伴可以參考一下2022-05-05如何在vuejs項(xiàng)目中使用md5加密密碼的實(shí)現(xiàn)
本文主要介紹了如何在vuejs項(xiàng)目中使用md5加密密碼的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08