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" > 
        < div
          v- 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- cropper
          v- 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- button
            v- 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 =  val
        console. 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. flipX
      let  scale =  dom. getAttribute ( 'data-scale' ) 
      scale =  scale ?  - scale :  - 1 
      this . $refs. cropper. scaleX ( scale) 
      dom. setAttribute ( 'data-scale' ,  scale) 
    } , 
    flipY ( )  { 
      const  dom =  this . $refs. flipY
      let  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. result
          
          this . $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>