vue 图片裁剪并回传显示

vue 图片裁剪并回传显示

数据页面::ResourceUrl="resourceUrl",注意,该代码是向裁剪页回传图片数据

<template>
  <div>
    <el-dialog :visible.sync="visible" :title="!dataForm.id ? $t('add') : $t('update')" :close-on-click-modal="false" :close-on-press-escape="false">
        <el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmitHandle()" label-width="120px">
        <el-form-item prop="coverUrl" :label="$t('course.coverUrl')">
            <div class="list-img-box"> 
              <img :src="courseUrl" style='width:120px;height:120px;border:none;' alt="自定义图片" @error="imgError()"><br/>
              <el-button type="text" @click="uploadPicture('flagImg')">修改图片</el-button>
            </div>
            <input type="hidden" v-model="dataForm.coverUrl" placeholder="请添加图片">
        </el-form-item>
        </el-form>
        <template slot="footer">
        <el-button @click="visible = false">{{ $t('cancel') }}</el-button>
        <el-button type="primary" @click="dataFormSubmitHandle()">{{ $t('confirm') }}</el-button>
        </template>
    </el-dialog>
    <!-- 弹窗, 上传文件 -->
  <upload v-if="uploadVisible" ref="upload" @uploadback="uploadUrl"></upload>
  <!-- 剪裁组件弹窗 -->
  <el-dialog title="裁切封面" :visible.sync="cropperModel" v-if="cropperModel" width="1130px" center append-to-body :before-close="dialogClose">
    <cropper-image :Name="cropperName" :ResourceUrl="resourceUrl" @uploadImgSuccess = "handleUploadSuccess" ref="child" :key="componentKey">
    </cropper-image>
  </el-dialog>
  <!--查看大封面-->
  <el-dialog title="查看大封面" :visible.sync="imgVisible" center>
    <img :src="imgName" v-if="imgVisible" style="width: 100%" alt="查看">
  </el-dialog>
  </div>
</template>

<script>
import debounce from 'lodash/debounce'
import CropperImage from './cropperImage'
export default {
  data () {
    return {
      visible: false,
      dataForm: {
        id: '',
        coverUrl: ''
      },
      courseUrl: '',
      // 裁切图片参数
      cropperModel: false,
      cropperName: '',
      resourceUrl: '',
      imgName: '',
      imgVisible: false,
      // 该参数作用是点击上传图片确定按钮后,刷新页面数据
      componentKey: 0
    }
  },
  components: {
      CropperImage
  },
  methods: {
    init () {
      this.visible = true
      this.$nextTick(() => {
        this.courseUrl = ''
        this.$refs['dataForm'].resetFields()
        if (this.dataForm.id) {
          this.getInfo()
        }
      })
    },
    // 封面设置
    uploadPicture (name) {
      this.cropperName = name
      this.cropperModel = true
    },
    // 点击叉号,关闭弹窗
    dialogClose () {
      this.cropperModel = false
      // 点击叉号,清除之前上传的图片
      this.resourceUrl = ''
      this.$emit('refreshDataList')
    },
    // 图片上传成功后
    handleUploadSuccess (data) {
      this.dataForm.coverUrl = data.url
      this.courseUrl = `${window.SITE_CONFIG['apiURL']}` + data.url 
      this.cropperModel = false
      // 清除之前上传的图片
      this.resourceUrl = ''
      this.$emit('refreshDataList')
    },
    // 默认头像
    imgError() {
      this.courseUrl = require('@/assets/img/course.png');
    },
    // 获取信息
    getInfo () {
      this.$http.get(`/cd/course/info/${this.dataForm.id}`).then(({ data: res }) => {
        if (res.code !== 0) {
          return this.$message.error(res.msg)
        }
        this.dataForm = {
          ...this.dataForm,
          ...res.data
        }
        if (res.data.coverUrl != null) {
            let prefixUrl = `${window.SITE_CONFIG['apiURL']}`
            this.courseUrl = prefixUrl + res.data.coverUrl
            // 回显的图片路径
            this.resourceUrl = res.data.coverUrl
        }
      }).catch(() => {})
    },
    // 上传文件
    uploadHandle () {
      this.uploadVisible = true
      let type = 0
      this.$nextTick(() => {
        this.$refs.upload.init(type)
      })
    },
    // 上传文件成功后,子组件回传到父组件资源id
    uploadUrl (val) {
        this.dataForm.coverUrl = val.resourceUrl
        let prefixUrl = `${window.SITE_CONFIG['apiURL']}`
        this.courseUrl = prefixUrl + val.resourceUrl
    },
    // 表单提交
    dataFormSubmitHandle: debounce(function () {
      this.$refs['dataForm'].validate((valid) => {
        if (!valid) {
          return false
        }
        this.$http[!this.dataForm.id ? 'post' : 'put']('/cd/course', this.dataForm).then(({ data: res }) => {
          if (res.code !== 0) {
            return this.$message.error(res.msg)
          }
          this.$message({
            message: this.$t('prompt.success'),
            type: 'success',
            duration: 500,
            onClose: () => {
              this.visible = false
              this.componentKey += 1;  
              this.$emit('refreshDataList')
            }
          })
        }).catch(() => {})
      })
    }, 1000, { 'leading': true, 'trailing': false })
  }
}
</script>

裁剪页面:

<template>
  <div class="cropper-content">
    <div class="cropper-box">
      <div class="cropper">
        <vue-cropper
            ref="cropper"
            :img="option.img"
            :outputSize="option.outputSize"
            :outputType="option.outputType"
            :info="option.info"
            :canScale="option.canScale"
            :autoCrop="option.autoCrop"
            :autoCropWidth="option.autoCropWidth"
            :autoCropHeight="option.autoCropHeight"
            :fixed="option.fixed"
            :fixedNumber="option.fixedNumber"
            :full="option.full"
            :fixedBox="option.fixedBox"
            :canMove="option.canMove"
            :canMoveBox="option.canMoveBox"
            :original="option.original"
            :centerBox="option.centerBox"
            :height="option.height"
            :infoTrue="option.infoTrue"
            :maxImgSize="option.maxImgSize"
            :enlarge="option.enlarge"
            :mode="option.mode"
            @realTime="realTime"
            @imgLoad="imgLoad">
        </vue-cropper>
      </div>
      <!--底部操作工具按钮-->
      <div class="footer-btn">
        <div class="scope-btn">
          <label class="btn" for="uploads" >选择封面</label>
          <input type="file" id="uploads" style="position:absolute; clip:rect(0 0 0 0);" accept="image/png, image/jpeg, image/gif, image/jpg" @change="selectImg($event)">
          <el-button size="mini" type="danger" plain icon="el-icon-zoom-in" @click="changeScale(1)">放大</el-button>
          <el-button size="mini" type="danger" plain icon="el-icon-zoom-out" @click="changeScale(-1)">缩小</el-button>
          <el-button size="mini" type="danger" plain @click="rotateLeft">↺ 左旋转</el-button>
          <el-button size="mini" type="danger" plain @click="rotateRight">↻ 右旋转</el-button>
        </div>
        <div class="upload-btn">
          <el-button size="mini" type="success" @click="uploadImg('blob')">上传封面 <i class="el-icon-upload"></i></el-button>
        </div>
      </div>
    </div>
    <!--预览效果图-->
    <div class="show-preview">
      <div :style="previews.div" class="preview">
        <img :src="previews.url" :style="previews.img">
      </div>
    </div>
  </div>
</template>

<script>
import { VueCropper } from 'vue-cropper'
import Cookies from 'js-cookie'
export default {
  name: 'CropperImage',
  components: {
    VueCropper
  },
  props: ['Name','ResourceUrl'],
  data () {
    return {
      name: this.Name,
      resourceUrl: this.ResourceUrl,
      previews: {},
      option: {
        img: '',             // 裁剪图片的地址
        outputSize: 1,       // 裁剪生成图片的质量(可选0.1 - 1)
        outputType: 'jpeg',  // 裁剪生成图片的格式(jpeg || png || webp)
        info: true,          // 图片大小信息
        canScale: true,      // 图片是否允许滚轮缩放
        autoCrop: true,      // 是否默认生成截图框
        autoCropWidth: 500,  // 默认生成截图框宽度
        autoCropHeight: 320, // 默认生成截图框高度
        fixed: true,         // 是否开启截图框宽高固定比例
        fixedNumber: [25, 16],  // 截图框的宽高比例
        full: false,         // false按原比例裁切图片,不失真
      //  fixedBox: true,      // 固定截图框大小,不允许改变
        canMove: false,      // 上传图片是否可以移动
        canMoveBox: true,    // 截图框能否拖动
        original: false,     // 上传图片按照原始比例渲染
        centerBox: false,    // 截图框是否被限制在图片里面
        height: true,        // 是否按照设备的dpr 输出等比例图片
        infoTrue: false,     // true为展示真实输出图片宽高,false展示看到的截图框宽高
        maxImgSize: 3000,    // 限制图片最大宽度和高度
        enlarge: 1,          // 图片根据截图框输出比例倍数
        mode: '500px 320px', // 图片默认渲染方式
        filename: '',
        //centerBox: false, // 截图框是否被限制在图片里面
        fixed: false, // 是否开启截图框宽高固定比例
      }
    }
  },
  mounted() {
    let prefixUrl = `${window.SITE_CONFIG['apiURL']}`
    let url =  prefixUrl + this.resourceUrl;
    // 回传的数据是base64,所以在这里将接收到的图片路径转base64格式
    this.toBase64(url)
  },
  methods: {
    toBase64(imgUrl) {
    // 一定要设置为let,不然图片不显示
    let image = new Image();
    // 解决跨域问题
    image.setAttribute('crossOrigin', 'anonymous');
    let imageUrl = imgUrl;
    image.src = imageUrl
    // image.onload为异步加载
    image.onload = () => {
        let canvas = document.createElement('canvas');
        canvas.width = image.width;
        canvas.height = image.height;
        let context = canvas.getContext('2d');
        context.drawImage(image, 0, 0, image.width, image.height);
        let quality = 0.8;
        // 这里的dataurl就是base64类型  
        // 使用toDataUrl将图片转换成jpeg的格式,不要把图片压缩成png,因为压缩成png后base64的字符串可能比不转换前的长!
        let dataurl = canvas.toDataURL('image/jpeg', quality);
        this.option.img = dataurl
        }
    },
    // 初始化函数
    imgLoad (msg) {
     // console.log(msg)
    },
    // 图片缩放
    changeScale (num) {
      num = num || 1
      this.$refs.cropper.changeScale(num)
    },
    // 向左旋转
    rotateLeft () {
      this.$refs.cropper.rotateLeft()
    },
    // 向右旋转
    rotateRight () {
      this.$refs.cropper.rotateRight()
    },
    // 实时预览函数
    realTime (data) {
      this.previews = data
    },
    // 选择图片  显示预览图
    selectImg (e) {
      let file = e.target.files[0]
      this.filename = file.name
      if (!/\.(jpg|jpeg|png|gif|JPG|PNG|GIF)$/.test(e.target.value)) {
        this.$message({
          message: '图片类型要求:jpeg、jpg、png',
          type: 'error'
        })
        return false
      }
      // 转化为blob
      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
        }
        this.option.img = data
      }
      // 转化为base64
      reader.readAsDataURL(file)
    },
    // 上传图片
    uploadImg (type) {
      if (type === 'blob') {
        // 获取截图的blob数据
        this.$refs.cropper.getCropBlob((data) => {
          let formData = new FormData()
          formData.append('file', data, this.filename)
          this.$http({
            url: `${window.SITE_CONFIG['apiURL']}/cd/resource/upload?token=${Cookies.get('token')}`,
            method: 'post',
            data: formData
          }).then(({data}) => {
            if (data.code === 0) {
              this.$message({
                message: '上传成功',
                type: 'success'
              })
              console.log("-------",data)
              let imgInfo = {
                name: this.Name,
                url: data.data.resourceUrl
              }
              this.$emit('uploadImgSuccess', imgInfo)
            } else {
              this.$message({
                message: '文件服务异常,请联系管理员!',
                type: 'error'
              })
            }
          })
        })
      }
    }
  }
}
</script>

<style scoped lang="scss">

.cropper-content{
  display: flex;
  display: -webkit-flex;
  justify-content: flex-end;
  .cropper-box{
    flex: 1;
    width: 100%;
    .cropper{
      width: auto;
      height: 400px;
    }
  }

  .show-preview{
    flex: 1;
    -webkit-flex: 1;
    display: flex;
    display: -webkit-flex;
    justify-content: center;
    .preview{
      overflow: hidden;
      border:1px solid #67c23a;
      background: #cccccc;
    }
  }
}
.footer-btn{
  margin-top: 30px;
  display: flex;
  display: -webkit-flex;
  justify-content: flex-end;
  .scope-btn{
    display: flex;
    display: -webkit-flex;
    justify-content: space-between;
    padding-right: 10px;
  }
  .upload-btn{
    flex: 1;
    -webkit-flex: 1;
    display: flex;
    display: -webkit-flex;
    justify-content: center;
  }
  .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;
  }
}
</style>


你可能感兴趣的:(Vue,vue.js,前端)