1.效果
2.使用组件
< Cropper ref = " cropperRef" :imgUrl = " url" @searchImg = " searchImg" > </ Cropper>
3.封装组件
< template> < el- dialog : title= "title" : visible. sync= "dialogVisible" width= "1000px" > < input ref= "input" type= "file" name= "image" @change= "setImage" / > < div class = "flex justify-around" > < div class = "w-480px h-270px flex justify-center items-center" > < divv- show= "!imgSrc" @click= "showFileChooser" class = "w-full h-full flex cursor-pointer justify-center items-center border-1px border-dashed border-gray-300 rounded-lg" > < i class = "font-size-20px el-icon-plus avatar-uploader-icon" > < / i> < / div> < ! -- : aspect- ratio= "16 / 16" -- > < vue- cropperv- show= "imgSrc" class = "w-full h-full" ref= "cropper" : src= "imgSrc" alt= "Source Image" @ready= "ready" @cropstart= "cropstart" @cropmove= "cropmove" @cropend= "cropend" @crop= "crop" @zoom= "zoom" preview= ".preview" : autoCropArea= "autoCropArea" > < / vue- cropper> < / div> < div class = "w-420px" > < div class = "font-bold color-#666 ml-20px mb-10px" > 预览< / div> < div v- show= "!imgSrc" class = "preview_empty ml-20px" > < / div> < div v- show= "imgSrc" class = "preview ml-20px" > < / div> < ! -- < div> 裁剪图片< / div> < div class = "cropped-image" > < el- image class = "h-180px" v- if = "cropImg" : src= "cropImg" alt= "Cropped Image" / > < div v- else class = "crop-placeholder" / > < / div> -- > < div class = "actions mt-10px ml-10px" > < el- button class = "mb-10px ml-10px" type= "primary" @click= "zoom(0.2)" size= "small" > 放大< / el- button> < el- button class = "mb-10px" type= "primary" @click= "zoom(-0.2)" size= "small" > 缩小< / el- button> < el- button class = "mb-10px" type= "primary" @click= "move(-10, 0)" size= "small" > 左移< / el- button> < el- button class = "mb-10px" type= "primary" @click= "move(10, 0)" size= "small" > 右移< / el- button> < el- button class = "mb-10px" type= "primary" @click= "move(0, -10)" size= "small" > 上移< / el- button> < el- button class = "mb-10px" type= "primary" @click= "move(0, 10)" size= "small" > 下移< / el- button> < el- button class = "mb-10px" type= "primary" @click= "rotate(90)" size= "small" > 旋转90 °< / el- button> < el- button class = "mb-10px" type= "primary" @click= "rotate(-90)" size= "small" > 旋转- 90 °< / el- button> < ! -- < el- button class = "mb-10px" type= "primary" @click= "flipX" size= "small" > 水平翻转< / el- button> < el- button class = "mb-10px" type= "primary" @click= "flipY" size= "small" > 垂直翻转< / el- button> -- > < ! -- < el- button class = "mb-10px" type= "success" @click= "cropImage" size= "small" > 搜索< / el- button> -- > < el- button class = "mb-10px" type= "primary" @click= "reset" size= "small" plain> 重置< / el- button> < el- buttonv- if = "!isHideFileChooser" class = "mb-10px" type= "success" @click= "showFileChooser" size= "small" plain> 更换图片< / el- button> < ! -- < el- button class = "mb-10px" type= "primary" @click= "getCropBoxData" size= "small" > 获取裁剪框数据< / el- button> < el- button class = "mb-10px" type= "primary" @click= "setCropBoxData" size= "small" > 设置裁剪框数据< / el- button> < el- button class = "mb-10px" type= "primary" @click= "getData" size= "small" > 获取裁剪数据< / el- button> < el- button class = "mb-10px" type= "primary" @click= "setData" size= "small" > 设置裁剪数据< / el- button> -- > < / div> < / div> < / div> < span slot= "footer" class = "dialog-footer" > < el- button size= "small" @click= "dialogVisible = false" > 取 消< / el- button> < el- button size= "small" type= "primary" @click= "cropImage" > 搜索< / el- button> < / span> < / el- dialog>
< / template> < script>
import VueCropper from 'vue-cropperjs'
import 'cropperjs/dist/cropper.css' export default { name : 'Cropper' , components : { VueCropper } , props : { title : { type : String, default : '图片框选' } , imgUrl : { type : String, default : '' } , autoCropArea : { type : Number, default : 0.6 } , isHideFileChooser : { type : Boolean, default : true } } , data ( ) { return { imgSrc : '' , dialogVisible : false , cropImg : '' } } , watch : { imgUrl ( val ) { if ( val) { this . imgSrc = valconsole. log ( '🚀 ~ imgUrl ~ this.imgSrc:' , this . imgSrc) } } } , methods : { open ( ) { if ( ! this . imgUrl) { this . imgSrc = '' } this . dialogVisible = true } , handleClose ( ) { this . $emit ( 'close' ) } , ready ( ) { } , cropImage ( ) { this . cropImg = this . $refs. cropper. getCroppedCanvas ( ) . toDataURL ( ) const base64Data = this . cropImg. split ( ',' ) [ 1 ] this . $emit ( 'searchImg' , base64Data) this . dialogVisible = false } , cropstart ( ) { } , cropmove ( ) { } , cropend ( ) { } , crop ( data ) { } , flipX ( ) { const dom = this . $refs. flipXlet scale = dom. getAttribute ( 'data-scale' ) scale = scale ? - scale : - 1 this . $refs. cropper. scaleX ( scale) dom. setAttribute ( 'data-scale' , scale) } , flipY ( ) { const dom = this . $refs. flipYlet scale = dom. getAttribute ( 'data-scale' ) scale = scale ? - scale : - 1 this . $refs. cropper. scaleY ( scale) dom. setAttribute ( 'data-scale' , scale) } , getCropBoxData ( ) { this . data = JSON . stringify ( this . $refs. cropper. getCropBoxData ( ) , null , 4 ) } , getData ( ) { this . data = JSON . stringify ( this . $refs. cropper. getData ( ) , null , 4 ) console. log ( '🚀 ~ getData ~ this.data:' , this . data) } , move ( offsetX, offsetY ) { this . $refs. cropper. move ( offsetX, offsetY) } , reset ( ) { this . $refs. cropper. reset ( ) } , rotate ( deg ) { this . $refs. cropper. rotate ( deg) } , setCropBoxData ( ) { if ( ! this . data) return this . $refs. cropper. setCropBoxData ( JSON . parse ( this . data) ) } , setData ( ) { if ( ! this . data) return this . $refs. cropper. setData ( JSON . parse ( this . data) ) } , setImage ( e ) { const file = e. target. files[ 0 ] if ( file. type. indexOf ( 'image/' ) === - 1 ) { alert ( 'Please select an image file' ) return } if ( typeof FileReader === 'function' ) { const reader = new FileReader ( ) reader. onload = ( event ) => { this . imgSrc = event. target. resultthis . $refs. cropper. replace ( event. target. result) } reader. readAsDataURL ( file) } else { alert ( 'Sorry, FileReader API not supported' ) } } , showFileChooser ( ) { this . $refs. input. click ( ) } , zoom ( percent ) { this . $refs. cropper. relativeZoom ( percent) } } , mounted ( ) { this . imgSrc = this . imgUrl}
}
< / script> < style lang= "scss" scoped>
input[ type= 'file' ] { display : none;
} . preview- area { width : 100 % ;
} . preview- area p { font- size: 1 . 25rem; margin : 0 ; margin- bottom: 1rem;
} . preview- area p: last- of - type { margin- top: 1rem;
} . preview { width : 270px; height : calc ( 270px * ( 9 / 16 ) ) ; overflow : hidden; background- color: #f5f5f5;
} . preview_empty { width : 270px; height : calc ( 270px * ( 9 / 16 ) ) ; overflow : hidden; background- color: #f5f5f5;
}
. crop- placeholder { width : 100 % ; height : 200px; background : #ccc;
} . cropped- image img { max- width: 100 % ;
}
< / style>