vue3.2中好用的图片裁剪工具


vue3.2中好用的图片裁剪工具

https://github.com/xyxiao001/vue-cropper

演示地址:按需保留需要的功能

http://github.xyxiao.cn/vue-cropper/example/
# 需要使用外层容器包裹并设置宽高

## 使用 注意: 需要关掉本地的mock服务, 不然图片转化会报错 

## vue 3 安装使用
```
npm install vue-cropper@next
import 'vue-cropper/dist/index.css'
import { VueCropper }  from "vue-cropper";
<template>
  <div>
    <el-row>
      <el-col :span="12">
        <!--        图片上传区域-->
        <div>
          <div style="width:100%;height: 60vh;">
            <!--      <vue-cropper-->
            <!--          autoCrop-->
            <!--          ref="cropperInstance"-->
            <!--          centerBox/>-->
            <vue-cropper
                style=""
                :canMove="option.canMove"
                autoCrop
                :img="option.img"
                :centerBox="option.centerBox"
                :original="option.original"
                @realTime="realTime"
                ref="cropperInstance"
                :outputType="option.outputType"
                centerBox/>
          </div>
        </div>
      </el-col>



 


                <div>

                </div>
              </div>

            </div>
            <!--          <div v-for="o in 4" :key="o" class="text item">{{ 'List item ' + o }}</div>-->

          </el-card>


        </div></el-col>
    </el-row>


    <!--    <el-button @click="getCropData" block ref="cropper">获取截图后的图片</el-button>-->


    <el-alert
        style="width: 50%"
        title="使用方法"
        type="success"
        description="点击图片,通过鼠标滑轮控制图片缩放大小;外部裁剪框可拖动进行拉伸大小;点击图片和裁剪框非重叠部分,可以移动图片位置"
        show-icon
    >
    </el-alert>

    <label class="btn" for="uploads">选择Logo文件</label>
    <input
        type="file"
        id="uploads"
        ref="uploadsFileInstall"
        style="position: absolute; clip: rect(0 0 0 0)"
        accept="image/png, image/jpeg, image/gif, image/jpg"
        @change="selectImg($event)"
    />
    <el-button
        size="small"
        type="primary" plain

        @click="changeScale(1)"
    >

      放大
    </el-button
    >
    <el-button
        size="small"
        type="primary" plain

        @click="changeScale(-1)"
    >
      缩小</el-button
    >
    <!-- <el-button size="mini" type="danger" plain icon="el-icon-delete" @click="clearImg">清空素材</el-button> -->
    <el-button size="small" type="primary" plain  @click="rotateLeft"
    >↺ 左旋转</el-button
    >

    <el-button size="small" type="primary" plain  @click="rotateRight"
    >↻ 右旋转</el-button
    >


    <el-button
        size="small"
        type="success"
        :loading="uploadLoading"
        @click="uploadImg('blob')"
    >上传logo <el-icon class="el-icon--right"><Upload /></el-icon></el-button>


    <!--    &lt;!&ndash;预览效果图&ndash;&gt;-->
    <!--    <div class="show-preview">-->
    <!--      <div class="show-preview-title">预览</div>-->
    <!--      <div :style="previews.div" class="preview">-->
    <!--        <img v-show="previews.url" :src="previews.url" :style="previews.img" />-->
    <!--      </div>-->
    <!--    </div>-->
    <!--    <div>-->
    <!--      {{previews}}-->
    <!--    </div>-->
    <!--    <div>-->
    <!--      <img v-show="previews.url" :src="previews.url" alt="">-->
    <!--    </div>-->
    <div>
      <p>预览截图框内容:像素点:width:{{previews.w}}px;height:{{previews.h}}px</p>
    </div>
    <section class="pre-item" style="border: 1px solid black;background: rgba(0,0,0,.5);" :style="{'width': previews.w + 'px', 'height': previews.h + 'px'}">

      <div class="show-preview" :style="{'width': previews.w + 'px', 'height': previews.h + 'px',  'overflow': 'hidden',
							'margin': '0px'}">
        <div :style="previews.div">
          <img :src="previews.url" :style="previews.img">
        </div>
      </div>
    </section>

    <div style="width: 100%;height: 40px;background-color: #ecdcde;display: flex;align-items: center;justify-content: center">
      <el-button type="primary">
        医院详情
      </el-button>

    </div>

    <div>
      <!--    分为2个区域:图片上传处理:医院信息编辑=1:1-->
      <div>
        <el-row >

          <el-col :span="12">
            <el-card>
              <template >
                <div class="clearfix">
                  <span>基本资料</span>
                </div>
              </template>
              <el-tabs v-model="activeTabsName">
                <el-tab-pane  label="医院资料" name="first">

                  <el-form ref="formEditRef" :model="hospForm.editForm"  label-width="80px">
                    <el-form-item label="医院id" prop="hospId" >
                      <el-input v-model="hospForm.editForm.hospId" disabled></el-input>
                    </el-form-item>
                    <el-form-item label="医院名称" prop="hospName" >
                      <el-input v-model="hospForm.editForm.hospName" ></el-input>
                    </el-form-item>
                    <el-form-item label="省ID" prop="provinceId" >
                      <el-input v-model="hospForm.editForm.provinceId" ></el-input>
                    </el-form-item>
                    <el-form-item label="市ID" prop="cityId" >
                      <el-input v-model="hospForm.editForm.cityId" ></el-input>
                    </el-form-item>
                    <el-form-item label="区ID" prop="areaId" >
                      <el-input v-model="hospForm.editForm.areaId" ></el-input>
                    </el-form-item>
                    <el-form-item>
                      <el-button type="primary" @click="commitEditHospInfo">保存</el-button>
                      <!--                    <el-button type="danger" @click="close">关闭</el-button>-->
                    </el-form-item>
                  </el-form>

                </el-tab-pane>

              </el-tabs>
            </el-card>
          </el-col>

          <el-col :span="12">
            <!--            <div>-->
            <!--              <img style="background: white" :src="elImgSrc" alt="">-->
            <!--              logo预览:{{elImgSrc}}-->
            <!--            </div>-->
            <div class="demo-image__preview">
              <el-image
                  v-if="hosp.info.reportLogo"
                  crossorigin='anonymous'
                  style="background: white"
                  :src="elImgSrc"
                  :initial-index="4"
                  fit="cover"
              >
              </el-image>
              {{hosp.info}}
            </div>
          </el-col>
        </el-row>
      </div>

    </div>

  </div>


</template>

<script setup>
import { Edit, Share, Delete, Search, Upload } from '@element-plus/icons-vue'
import "vue-cropper/dist/index.css";
import { VueCropper } from "vue-cropper";
import {onMounted, reactive, ref, watch} from "vue";
import axios from "axios";
import {editHospByBtn, getHospByBtn, uploadLogo} from "../../api/HospInfoByBtn/HospInfoByBtn";
import {ElMessage, ElMessageBox} from "element-plus";
import moment from "moment";
import router from "../../router";

const option = reactive({
  img: '',             //裁剪图片的地址
  outputSize: 1,       //裁剪生成图片的质量(可选0.1 - 1)
  outputType: 'png',  //裁剪生成图片的格式(jpeg || png || webp)
  info: true,          //图片大小信息
  canScale: true,      //图片是否允许滚轮缩放
  autoCrop: false,      //是否默认生成截图框
  autoCropWidth: 230,  //默认生成截图框宽度
  autoCropHeight: 35, //默认生成截图框高度
  fixed: false,         //是否开启截图框宽高固定比例
  fixedNumber: [7, 4], //截图框的宽高比例
  full: true,         //false按原比例裁切图片,不失真
  fixedBox: true,      //固定截图框大小,不允许改变
  canMove: true,      //上传图片是否可以移动
  canMoveBox: true,    //截图框能否拖动
  original: true,     //上传图片按照原始比例渲染
  centerBox: false,    //截图框是否被限制在图片里面
  height: true,        //是否按照设备的dpr 输出等比例图片
  infoTrue: false,     //true为展示真实输出图片宽高,false展示看到的截图框宽高
  maxImgSize: 3000,    //限制图片最大宽度和高度
  enlarge: 1,          //图片根据截图框输出比例倍数
  mode: '280px 160px'  //图片默认渲染方式
})
const chooseImageType = ref('jpg')
const cropper=ref(null)
const cropperInstance = ref(null) // 用于标识cropper组件实例  vue2.x 中的ref
const uploadLoading = ref(false)
const previews = ref({})
const previewStyle3 = ref({})



const activeTabsName =ref('first')
const test=JSON.parse(window.sessionStorage.getItem("arr_start_menuRouter_NoBtn"))
const hosp=reactive({
  info:{
    reportLogo:''
  }

})

//上传图片需要添加的token
const  SysUserToken= window.sessionStorage.getItem("SysUserToken")
const tokenHeader=ref({accessToken:SysUserToken})
// const elImgSrc=ref('')
const hospForm=reactive({
  editForm:{
    hospId:'',
    hospName:'',
    provinceId:'',
    cityId:'',
    areaId:'',
  }
})
const formEditRef= ref(null)
const size = ref('')
const editHospDialogVisible=ref(false)
//时间处理:
const dateFormat=(date)=>{
  return moment(date).format('YYYY-MM-DD HH:mm:ss') // 这里可修改的格式
}

//点击编辑医院信息
const  editHospInfo=()=>{
  //打开对话框
  hospForm.editForm.hospId=hosp.info.hospId
  hospForm.editForm.hospName=hosp.info.hospName
  hospForm.editForm.provinceId=hosp.info.provinceId
  hospForm.editForm.cityId=hosp.info.cityId
  hospForm.editForm.areaId=hosp.info.areaId
  editHospDialogVisible.value=true
}

//监听:编辑医院信息对话框关闭:清空表单,还原警告
const editHospDialogClosed=()=>{
  //清空表单
  formEditRef.value.resetFields();
}

//点击取消 编辑医院信息
const cancleEidtHospInfo=()=>{
  //清空表单
  formEditRef.value.resetFields();
  //关闭弹出框
  editHospDialogVisible.value=false
}
//编辑角色:点击保存按钮,提交所有的医院信息
const commitEditHospInfo=()=>{
  //校验字段

  //提交数据
  const param ={
  }
  param.hospId=hospForm.editForm.hospId
  param.hospName=hospForm.editForm.hospName
  param.provinceId=hospForm.editForm.provinceId
  param.cityId=hospForm.editForm.cityId
  param.areaId=hospForm.editForm.areaId

  //发起请求
  editHospByBtn(param).then(res =>{

    if (res.code === 200) {
      ElMessage({
        message: "修改医院信息成功",
        type: 'success',
        showClose: true,
        duration: 1000,
      })
      //清空表单
      // formEditRef.value.resetFields()
      //刷新列表
      getHospInfo()
      // // console.log("重新请求列表成功")
      // editHospDialogVisible.value =false //关闭对话框
    }else {
      ElMessage({
        message: "修改医院信息失败"+res.msg,
        type: 'error',
        showClose: true,
        duration: 1000,
      })
      //跳出

    }

  })
}


//编辑角色:点击提交按钮,提交所有的医院信息
const commitEditRoleInfo=()=>{
  //校验字段

  //提交数据
  const param ={
  }
  param.hospId=hospForm.editForm.hospId
  param.hospName=hospForm.editForm.hospName
  param.provinceId=hospForm.editForm.provinceId
  param.cityId=hospForm.editForm.cityId
  param.areaId=hospForm.editForm.areaId

  //发起请求
  editHospByBtn(param).then(res =>{

    if (res.code === 200) {
      ElMessage({
        message: "修改医院信息成功",
        type: 'success',
        showClose: true,
        duration: 1000,
      })
      //清空表单
      formEditRef.value.resetFields()
      //刷新列表
      getHospInfo()
      // console.log("重新请求列表成功")
      editHospDialogVisible.value =false //关闭对话框
    }else {
      ElMessage({
        message: "修改医院信息失败"+res.msg,
        type: 'error',
        showClose: true,
        duration: 1000,
      })
      //跳出

    }

  })
}
//获取医院信息
const getHospInfo=()=>{
  //校验字段
  //提交数据
  const param ={
  }
  param.hospId=hosp.info.hospId

  //发起请求
  getHospByBtn(param).then(res =>{

    if (res.code === 200) {
      //更新医院信息
      hosp.info=res.data
      hospForm.editForm.hospId=hosp.info.hospId
      hospForm.editForm.hospName=hosp.info.hospName
      hospForm.editForm.provinceId=hosp.info.provinceId
      hospForm.editForm.cityId=hosp.info.cityId
      hospForm.editForm.areaId=hosp.info.areaId
      //更新图片信息
      elImgSrc.value='http://121.201.93.45:19002/reportLogo/'+hosp.info.reportLogo
    }else {
      ElMessage({
        message: "获取医院信息失败"+res.msg,
        type: 'error',
        showClose: true,
        duration: 1000,
      })
      //跳出
    }
  })
}
const handleClose =(done)=>{
  // ElMessageBox.confirm('Are you sure to close this dialog?')
  ElMessageBox.confirm('您确定要关闭此对话框吗?')
      .then(() => {
        done()
      })
      .catch(() => {
        // catch error
      })
}
// 图片上传成功之后的回调函数
const uploadFileSuccess=(response, file, fileList)=>{
  // console.log(response)
  if(response.code===200){
    ElMessage({
      message: "上传图片成功",
      type: 'success',
      showClose: true,
      duration: 1000,
    })
    getHospInfo()
  }else {
    ElMessage({
      message: response.msg,
      type: 'error',
      showClose: true,
      duration: 1000,
    })
  }
}
// const elImgSrc=ref('')
const elImgSrc=ref('http://121.201.93.45:19002/reportLogo/'+hosp.info.reportLogo)
watch(hosp.info,()=>{
  elImgSrc.value='http://121.201.93.45:19002/reportLogo/'+hosp.info.reportLogo
})

//文件上传之前进行校验
const beforeAvatarUpload=(file, fileList)=>{

  //获取上传文件的后缀名
  const fileSuffix = file.name.substring(file.name.lastIndexOf(".") + 1);

  const whiteList = ["jpeg", "png", "bmp", "jpg"];

  if (whiteList.indexOf(fileSuffix) === -1) {
    ElMessage({
      message: "文件格式错误,选上传:.jpeg,.png,.bmp,.jpg。",
      type: 'error',
      showClose: true,
      duration: 1000,
    })
    file.abort() //取消上传请求
    return;
  }



  //获取上传文件大小
  let imgSize = Number(file.size / 1024 );
  if (imgSize > 200) {
    ElMessage({
      message: "文件大小不能超过200k,请重新上传。",
      type: 'error',
      showClose: true,
      duration: 1000,
    })
    file.abort() //取消上传请求
    return;
  }else {

  }

}


//初始化
onMounted(() => {

  /**
   * 1、判断是否是路由跳转
   */
  if(router.currentRoute.value.params.Report_ByHospital){
    hosp.info=JSON.parse(router.currentRoute.value.params.Report_ByHospital)
    elImgSrc.value='http://121.201.93.45:19002/reportLogo/'+hosp.info.reportLogo
    getHospInfo()
  }

  /**
   * 2、判断是否有缓存:医院管理
   */
  else if(JSON.parse(window.sessionStorage.getItem("router_Report_HospInfoByBtn")) ){
    hosp.info=JSON.parse(window.sessionStorage.getItem("router_Report_HospInfoByBtn"))
    elImgSrc.value='http://121.201.93.45:19002/reportLogo/'+hosp.info.reportLogo
    getHospInfo()
  }
  else {
    hosp.info.hospId=''
    hosp.info.reportLogo=''
    hosp.info.hospName=''
    hosp.info.provinceId=''
    hosp.info.cityId=''
    hosp.info.areaId=''
    elImgSrc.value=''
  }
  //医院信息赋值
  hospForm.editForm.hospId=hosp.info.hospId
  hospForm.editForm.hospName=hosp.info.hospName
  hospForm.editForm.provinceId=hosp.info.provinceId
  hospForm.editForm.cityId=hosp.info.cityId
  hospForm.editForm.areaId=hosp.info.areaId

})



const realTime = function(data){
  previews.value = data
  //固定高宽 计算 :按照比例计算
  let x_scale=308 / previews.value.w
  let y_scale=44 / previews.value.h
  // console.log("previews.w",previews.value.w)
  // console.log("previews.h",previews.value.h)
  // console.log("x_scale",x_scale)
  // console.log("y_scale",y_scale)
  // let x_scale=0.5
  // let y_scale=0.5
  previewStyle3.value = {
    width: previews.value.w + "px",
    height: previews.value.h + "px",
    overflow: "hidden",
    margin: "0",
    transform:"scale("+x_scale+","+y_scale+")",
    background:"white",
    // let zoom_value=100 / previews.value.w
    // let zoom_value1=100 / zoom_value.w
  }}
const getCropData=(data)=>{
  console.log("data:",data)
  console.log(cropper.value)
  cropper.value.getCropData(data=>{
    console.log(data)
  })
}


// 选择图片
const selectImg = function(e){
  if(!e.target.files.length) return
  if (!/\.(jpg|jpeg|png|JPG|PNG)$/.test(e.target.value)) {
    alert('图片类型要求:jpeg、jpg、png')
    return false
  }
  let file = e.target.files[0]
  let strArr = file.name.split('.')
  chooseImageType.value = strArr[strArr.length-1]
  let reader = new FileReader()
  reader.onload = (e) => {
    let data
    if (typeof e.target.result === 'object') {
      data = window.URL.createObjectURL(new Blob([e.target.result]))
    } else {
      data = e.target.result
    }
    option.img = data
  }
  //转化为base64
  reader.readAsDataURL(file)
}
// 图片缩放
const changeScale = function(num){
  num = num || 1
  cropperInstance.value.changeScale(num)
}
// 向左旋转
const rotateLeft = function(){
  cropperInstance.value.rotateLeft()
}
// 向右旋转
const rotateRight = function(){
  cropperInstance.value.rotateRight()
}
// 上传图片
const uploadImg = function(type){
  if(type !== 'blob') return
  cropperInstance.value.getCropBlob(async (data)=>{
    let formData = new FormData();
    formData.append('logoFile',data,`DX.${chooseImageType.value}`)
    formData.append('hospId',hosp.info.hospId)
    //调用axios上传   将请求地址改为自己图片上传的地址
    uploadLoading.value = true
    uploadLogo(formData).then(res =>{
      if (res.code === 200) {
        ElMessage({
          message: "logo上传成功",
          type: 'success',
          showClose: true,
          duration: 1000,
        })
        getHospInfo()
        uploadLoading.value = false
      }else {
        ElMessage({
          message: +res.msg,
          type: 'error',
          showClose: true,
          duration: 1000,
        })
        uploadLoading.value = false

      }
    })

  })
}

</script>
<style lang="less" scoped>
/deep/ .cropper-move{
  background: rgba(0,0,0,.5)!important;
}
.btn {
  outline: none;
  display: inline-block;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  -webkit-appearance: none;
  text-align: center;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  outline: 0;
  -webkit-transition: .1s;
  transition: .1s;
  font-weight: 500;
  padding: 8px 15px;
  font-size: 12px;
  border-radius: 3px;
  color: #fff;
  background-color: #409EFF;
  border-color: #409EFF;
  margin-right: 10px;
}

.show-preview{


  background-color: #FFFFFF;

}

</style>


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM