本文主要使用了
element-ui
的圖片上傳組件獲取圖片思犁,然后使用cropper.js
進(jìn)行圖片裁剪逊笆,在裁剪完以后進(jìn)行格式轉(zhuǎn)換拂苹,然后自行圖片上傳,文中的css使用了stylus
編譯矮湘,如果不是請自行更改
1.插件安裝
npm install cropperjs --save
element-ui
的安裝就不予以贅述了斟冕,主要使用了element-ui的圖片上傳以及$message
2.組件編寫
- 目錄新建
在components
文件夾下新建upload
文件夾口糕,然后在upload
文件夾下新建 cropperBox.vue
以及 upCover.vue
- 編寫
cropperBox.vue
在cropperBox.vue
中寫入以下內(nèi)容,(finishCropImage
方法中的blob
的數(shù)據(jù)格式請自行選擇以下兩種缅阳,第一種是blob,第二種是普通文件方式。)
<template>
<div class="cropper-wrap">
<div class="cropper-alert-mask" :class="{ show: imgHasLoad }"></div>
<div class="cropper-alert" :class="{ show: imgHasLoad }">
<div class="cropper">
<span class="layout-icon-wrap"><i class="el-icon-circle-close" @click="imgHasLoad=false"></i></span>
<div class="cropper-box">
<img ref="uploadPreview" style="width:100px;height:auto;">
</div>
<div class="cropper-res-wrap">
<div class="cropper-res" id="cropperRes">
<img style="width:100px;height:100px;">
</div>
</div>
</div>
<div class="cropper-btns-wrap">
<el-progress
:text-inside="true"
:stroke-width="30"
:percentage="uploadProgress">
</el-progress>
<button
type="button"
class="cropper-btn"
@click="finishCropImage"
:disabled="btnTips.disable"
:class="{'btn-bg': uploading}">
{{ btnTips.value }}
</button>
</div>
</div>
</div>
</template>
<script>
import Cropper from 'cropperjs'
export default {
name: 'cropper-box',
props: {
options: {
default: {
aspectRatio: 1 / 1,
preview: '#cropperRes',
zoomOnWheel: false,
minCropBoxWidth: 50
}
},
uploadProgress: {
default: 0
}
},
data () {
return {
cropper: null,
imgHasLoad: false,
cropperHasInit: false,
uploading: false,
rawFile: null
}
},
watch: {
imgHasLoad (val) {
if (!val) {
this.uploading = false
}
}
},
computed: {
btnTips () {
if (this.uploading) {
return {
value: '正在上傳十办,請稍等',
disable: true
}
}
return {
value: '裁剪完成秀撇,立即上傳',
disable: false
}
}
},
methods: {
show () {
this.imgHasLoad = true
},
close () {
this.imgHasLoad = false
},
loadCropper (rawFile) {
this.rawFile = rawFile
const URL = window.URL || window.webkitURL
const blobURL = URL.createObjectURL(rawFile)
var image = this.$refs.uploadPreview
if (!this.cropper) this.cropper = new Cropper(image, this.options)
this.cropper.reset().replace(blobURL)
},
// 完成裁剪,將文件進(jìn)行格式轉(zhuǎn)換向族,發(fā)送給父組件呵燕,請自行選擇普通文件格式還是blob格式,格式轉(zhuǎn)換方法已封裝件相,請看下面的兩個方法
finishCropImage () {
this.uploading = true
const croppedCanvas = this.cropper.getCroppedCanvas()
const croppedDataUrl = croppedCanvas.toDataURL(this.rawFile.type)
const blob = this.base64toFile(croppedDataUrl)
this.$emit('finishCropImage', blob)
},
// dataUrl 轉(zhuǎn) blob
dataURLtoBlob (dataurl) {
/* eslint-disable */
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1];
var bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type:mime});
/* eslint-enable */
},
//base64轉(zhuǎn)為普通文件格式
base64toFile (dataurl, filename = 'file') {
let arr = dataurl.split(',')
let mime = arr[0].match(/:(.*?);/)[1]
let suffix = mime.split('/')[1]
let bstr = atob(arr[1])
let n = bstr.length
let u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], `${filename}.${suffix}`, {
type: mime
})
},
}
}
</script>
<style lang="stylus">
@import "cropperjs/dist/cropper.min.css"
.cropper-wrap
.cropper-alert-mask
position: fixed
top: 0
left: 0
right: 0
bottom: 0
z-index: 2000
background-color: rgba(#000000, .5)
visibility: hidden
height: 0
transition: all .3s ease
.cropper-alert-mask.show
visibility: visible
height: 100%
.cropper-alert
opacity: 0
transition: all .3s ease
visibility: hidden
padding: 10px
position: fixed
z-index: 2000
top: 50px
left: 50%
transform: translateX(-50%) scale(2)
background-color: #ffffff
border-radius: 5px
overflow: hidden
width: 100%
height: 100%
max-width: 600px
max-height: 530px
&.show
opacity: 1
visibility: visible
transform: translateX(-50%) scale(1)
.cropper
position: relative
max-width: 600px
max-height: 460px
height: 100%
padding: 10px
padding-right: 120px
@media (max-width: 1324px)
padding-top: 120px
padding-right: 10px
background-color: #f9fbfc
.layout-icon-wrap
position: absolute
cursor: pointer
right: 0px
top: 0px
font-size: 20px
.cropper-box
position: relative
width: 100%
height: 100%
background-color: #ffffff
.cropper-res-wrap
position: absolute
top: 50%
transform: translateY(-50%)
@media (max-width: 1324px)
top: 0
left: 50%
transform: translateX(-50%)
right: 0
width: 100px
height: auto
padding: 10px
background-color: #a8a8a8
box-sizing: content-box
.cropper-res
width: 100px
height: 100px
overflow: hidden
background-color: #ffffff
.cropper-btns-wrap
position: relative
margin-top: 20px
.cropper-btn
position: absolute
left: 0
top: 0
width: 100%
height: 30px
line-height: 1
background: #ffffff
border: 1px solid #e1e1e1
border-radius: 15px
color: #666666
cursor: pointer
.btn-bg
background: #FF000000
</style>
- 編寫
upCover.vue
在upCover.vue
中寫入以下內(nèi)容,(finishCropImage方法中請自行補(bǔ)充圖片上傳調(diào)用接口的方法)
<template>
<div
class="cover-upload-wrap"
ref=coverOutWrap
:style="{
width: width ? (width + 'px') : '100%',
height: calcHeight + 'px',
maxWidth: maxWidth ? (maxWidth + 'px') : '100px',
maxHeight: maxHeight ? (maxHeight + 'px') : '100px'
}">
<el-upload
ref="upload"
class="cover-uploader"
:show-file-list="false"
:before-upload="beforeVipImageUpload"
:auto-upload="false"
:on-change="onFileChange"
:on-progress="onUploadProgress">
<div class="img-wrap">
<img :src="imageUrl" class="cover" v-if="imageUrl">
<div class="img-mask-default" :class="{'img-mask': imageUrl}">
<i class="el-icon-upload"></i>
<div>{{ tip }}</div>
</div>
</div>
</el-upload>
<cropperBox
ref="cropperBox"
:options="options"
:uploadProgress="uploadProgress"
@finishCropImage="finishCropImage">
</cropperBox>
</div>
</template>
<script>
import uploadImage from "../../mixins/uploadImage";
import cropperBox from './cropperBox'
import {upload} from "../../api/base";
export default {
name: 'up-cover',
mixins:[uploadImage],
components: {
cropperBox
},
props: {
defaultImg: String,
ratio: { // 裁剪結(jié)果寬高比
default: 1
},
width: [Number,String],
height: [Number,String],
WHRatio: { // 組件寬高比
default: 1
},
cropBoxResizable:Boolean, //是否可以修改裁剪框的尺寸
maxWidth: String,
maxHeight: String,
tip: {
default: '上傳圖片'
},
maxSize: { // 最大選擇圖片的大小再扭,單位M
default: 3
}
},
data () {
return {
cropper: null,
newFile: null,
options: {
aspectRatio: 2.166,
preview: '#cropperRes',
zoomOnWheel: false,
cropBoxResizable:false,
minCropBoxWidth: 50,
viewMode:3
},
token: {},
uploadProgress: 0,
calcHeight: 0
}
},
created() {
this.options.aspectRatio = this.ratio;
this.options.cropBoxResizable = this.cropBoxResizable;
if (this.height) {
this.calcHeight = this.height
}
},
computed: {
imageUrl () {
return this.defaultImg
}
},
mounted() {
if (!this.calcHeight) {
if (this.width) {
this.calcHeight = this.width / this.WHRatio
} else {
this.calcHeight = this.$refs.coverOutWrap.offsetWidth / this.WHRatio
}
}
},
methods: {
//截取圖片上傳的事件,有圖片的情況就打開裁剪框夜矗,并且將文件傳入到裁剪框中
onFileChange (file, fileList) {
if (file.status === 'ready') {
this.$refs.cropperBox.show();
this.$refs.cropperBox.loadCropper(file.raw)
}
},
//文件裁剪泛范,nerFile就是最終拿到的文件,自行調(diào)接口進(jìn)行圖片上傳
finishCropImage (newFile) {
this.newFile = newFile;
//圖片上傳調(diào)接口請自行補(bǔ)充
},
//上傳圖片之前的大小檢測紊撕,文件大小通過prop傳遞罢荡,可在組件使用自定義文件大小限制
beforeVipImageUpload(file){
const isLt3M = file.size / 1024 / 1024 < this.maxSize;
if (!isLt3M) {
this.$message.error('上傳圖片大小不可大于' + this.maxSize + 'M');
}
return isLt3M;
let uploadFile = new window.File([this.newFile], file.name, { type: this.newFile.type });
uploadFile.uid = this.newFile.uid;
return Promise.resolve(uploadFile)
},
//文件上傳進(jìn)度
onUploadProgress (event, file, fileList) {
this.uploadProgress = parseInt(event.percent) - 1
}
}
}
</script>
<style lang="stylus">
.cover-upload-wrap
position: relative
width: 100%
max-width: 300px
height: 150px
border-radius: 5px
.cover-uploader
width: 100%
height: 100%
.el-upload
width: 100%
height: 100%
overflow: hidden
border-radius: 5px
cursor: pointer
border: 1px solid #dddddd
.img-wrap
position: relative
width: 100%
height: 100%
&:hover
.img-mask-default
opacity: 1
background-color: rgba(0, 0, 0, 0.5)
color: #ffffff
.cover
position: relative
width: 100%
height: 100%
border-radius: 5px
.img-mask-default
position: absolute
left: 0
top: 0
width: 100%
height: 100%
padding-left: 10px
padding-right: 10px
background-color: #ffffff
color: #555555
display: flex
flex-direction: column
justify-content: center
font-size: 12px
transition: all .2s linear
.el-icon-upload
font-size: 18px
.img-mask
opacity: 0
</style>
使用方法
- 引入插件
import UP from '@/components/upload/upCover'
export default {
components:{UP},
}
- 在頁面中使用
pictureUrl
就是圖片上傳成功以后顯示的回調(diào)地址,請自行填寫对扶,maxSize可以限定上傳圖片時候的尺寸大小区赵,width和height限定組件大小,
<UP class="upload-cover"
:default-img="pictureUrl?pictureUrl:''"
ratio="2.166"
:cropBoxResizable="true"
width="156"
height="72"
tip="上傳等級圖標(biāo)"
maxSize="3"
@uploadSuccess="uploadSuccess">
</UP>
在uploadSuccess
方法中可以拿到圖片上傳成功以后的回調(diào)浪南,具體操作自行補(bǔ)充啦
uploadSuccess(res){
//this.pictureUrl=res.data
},
更多操作
javascript操作
this.myCropper.getCroppedCanvas().toDataURL('image/jpeg') //拿到裁剪后的base64的圖片
this.myCropper.getCropBoxData(); //獲取裁剪框數(shù)據(jù)
this.myCropper.setCropBoxData(); //設(shè)置裁剪框數(shù)據(jù)
this.myCropper.getCanvasData(); //獲取圖片數(shù)據(jù)
this.myCropper.setCanvasData(); //設(shè)置圖片數(shù)據(jù)
配置對象
-
viewMode
視圖控制- 0 無限制
- 1 限制裁剪框不能超出圖片的范圍
- 2 限制裁剪框不能超出圖片的范圍 且圖片填充模式為 cover 最長邊填充
- 3 限制裁剪框不能超出圖片的范圍 且圖片填充模式為 contain 最短邊填充
-
dragMode
拖拽圖片模式-
crop
形成新的裁剪框 -
move
圖片可移動 -
none
什么也沒有
-
-
initialAspectRatio
裁剪框?qū)捀弑鹊某跏贾?默認(rèn)與圖片寬高比相同 只有在aspectRatio沒有設(shè)置的情況下可用 -
aspectRatio
設(shè)置裁剪框為固定的寬高比 -
data
之前存儲的裁剪后的數(shù)據(jù) 在初始化時會自動設(shè)置 只有在autoCrop設(shè)置為true時可用 -
preview
預(yù)覽 設(shè)置一個區(qū)域容器預(yù)覽裁剪后的結(jié)果Element, Array (elements), NodeList or String (selector)
-
responsive
在窗口尺寸調(diào)整后 進(jìn)行響應(yīng)式的重渲染 默認(rèn)true -
restore
在窗口尺寸調(diào)整后 恢復(fù)被裁剪的區(qū)域 默認(rèn)true -
checkCrossOrigin
檢查圖片是否跨域 默認(rèn)true 如果是 會在被復(fù)制的圖片元素上加上屬性crossOrigin 并且在src上加上一個時間戳 避免重加載圖片時因為瀏覽器緩存而加載錯誤 -
checkOrientation
檢查圖片的方向信息(僅JPEG圖片有)默認(rèn)true 在旋轉(zhuǎn)圖片時會對圖片方向值做一些處理 以解決IOS設(shè)備上的一些問題 -
modal
是否顯示圖片和裁剪框之間的黑色蒙版 默認(rèn)true -
guides
是否顯示裁剪框的虛線 默認(rèn)true -
center
是否顯示裁剪框中間的 ‘+’ 指示器 默認(rèn)true -
highlight
是否顯示裁剪框上面的白色蒙版 (很淡)默認(rèn)true -
background
是否在容器內(nèi)顯示網(wǎng)格狀的背景 默認(rèn)true -
autoCrop
允許初始化時自動的裁剪圖片 配合 data 使用 默認(rèn)true -
autoCropArea
設(shè)置裁剪區(qū)域占圖片的大小 值為 0-1 默認(rèn) 0.8 表示 80%的區(qū)域 -
movable
是否可以移動圖片 默認(rèn)true -
rotatable
是否可以旋轉(zhuǎn)圖片 默認(rèn)true -
scalable
是否可以縮放圖片(可以改變長寬) 默認(rèn)true -
zoomable
是否可以縮放圖片(改變焦距) 默認(rèn)true -
zoomOnTouch
是否可以通過拖拽觸摸縮放圖片 默認(rèn)true -
zoomOnWheel
是否可以通過鼠標(biāo)滾輪縮放圖片 默認(rèn)true -
wheelZoomRatio
設(shè)置鼠標(biāo)滾輪縮放的靈敏度 默認(rèn) 0.1 -
cropBoxMovable
是否可以拖拽裁剪框 默認(rèn)true -
cropBoxResizable
是否可以改變裁剪框的尺寸 默認(rèn)true -
toggleDragModeOnDblclick
是否可以通過雙擊切換拖拽圖片模式(move和crop)默認(rèn)true 當(dāng)拖拽圖片模式為none時不可切換 該設(shè)置必須瀏覽器支持雙擊事件 -
minContainerWidth(200)笼才、minContainerHeight(100)、minCanvasWidth(0)络凿、minCanvasHeight(0)患整、minCropBoxWidth(0)、minCropBoxHeight(0)
容器喷众、圖片各谚、裁剪框的 最小寬高 括號內(nèi)為默認(rèn)值 注意 裁剪框的最小高寬是相對與頁面而言的 并非相對圖片
方法
-
crop()
手動顯示裁剪框 -
reset()
重置圖片和裁剪框為初始狀態(tài) -
replace(url[, hasSameSize])
替換圖片路徑并且重建裁剪框-
url
新路徑 -
hasSameSize
默認(rèn)值false 設(shè)置為true表示新老圖片尺寸一樣 只需要更換路徑無需重建裁剪框
-
-
enable()
解凍 裁剪框 -
disable()
凍結(jié) 裁剪框 -
destroy()
摧毀裁剪框并且移除cropper實例 -
move(offsetX[, offsetY])
移動圖片指定距離 一個參數(shù)代表橫縱向移動距離一樣 -
moveTo(x[, y])
移動圖片到一個指定的點(diǎn) 一個參數(shù)代表橫縱向移動距離一樣 -
zoom(ratio)
縮放 ratio大于零是放大 小于零縮小 -
zoomTo(ratio[, pivot])
縮放并設(shè)置中心點(diǎn)的位置 -
rotate(degree)
旋轉(zhuǎn) 類似css -
rotateTo(degree)
旋轉(zhuǎn)到絕對角度 -
scale(scaleX[, scaleY])、scaleX(scaleX)到千、scaleY(scaleY)
縮放 一個參數(shù)代表橫縱向縮放值一樣 -
getData([rounded])
返回裁剪區(qū)域基于原圖片!原尺寸!的位置和尺寸 rounded默認(rèn)為false 表示是否顯示四舍五入后的數(shù)據(jù) 有了這些數(shù)據(jù)可以直接在原圖上進(jìn)行裁剪顯示 -
setData(data)
改變裁剪區(qū)域基于原圖的位置和尺寸 僅當(dāng)viewMode 不為0時有效 -
getContainerData()昌渤、getImageData()、getCanvasData()憔四、setCanvasData(data)膀息、getCropBoxData()、setCropBoxData(data)
容器了赵、圖片容器(畫布)潜支、圖片、裁剪區(qū)域相對容器的數(shù)據(jù)設(shè)置和獲取 -
getCroppedCanvas([options])
得到被裁剪圖片的一個canvas對象 options設(shè)置這個canvas的一些數(shù)據(jù)-
width柿汛、height冗酿、minWidth、minHeight、maxWidth裁替、maxHeight项玛、fillColor、imageSmoothingEnabled
(圖片是否是光滑的 默認(rèn)true)弱判、imageSmoothingQuality(圖片的質(zhì)量 默認(rèn)low 還有medium襟沮、high)
-
-
setAspectRatio(aspectRatio)
改變裁剪區(qū)域的寬高比 -
setDragMode([mode])
設(shè)置拖拽圖片模式
事件
-
ready
渲染前(圖片已經(jīng)被加載、cropper實例已經(jīng)準(zhǔn)備完畢)的準(zhǔn)備工作事件 -
cropstart昌腰、cropmove开伏、cropend、crop
開始畫裁剪框(或畫布)遭商、畫裁剪框(或畫布)的中途硅则、裁剪框(或畫布)畫完、進(jìn)行裁剪事件 event.detail.originalEvent株婴、event.detail.action- 當(dāng)autoCrop為true crop事件會在ready之前觸發(fā)
-
zoom
裁剪框縮放事件
本文參考于https://www.cnblogs.com/eightFlying/p/cropper-demo.html