vue+element上传多个图片裁剪组件

先看实现功能:

 

 

 首先npm i vue-cropper下载插件

组件index.vue

<template>
  <div>
    <el-upload ref="multiImageUpload"
               :action="uploadImgUrl"
               :headers="headers"
               multiple
               accept="image/png, image/jpeg"
               list-type="picture-card"
               :on-change="handleChange"
               :on-preview="handlePictureCardPreview"
               :on-remove="handleRemove"
               :file-list="imageList"
               :auto-upload="false"
               :http-request="upload"
               :show-file-list="true"
               v-loading="loading"
               element-loading-text="拼命上传中"
               >
      <i class="el-icon-plus"></i>
    </el-upload>
    <el-dialog :visible.sync="previewImage" title="预览" width="800" append-to-body>
      <img :src="previewImageUrl" style="display: block; max-width: 100%; margin: 0 auto;">
    </el-dialog>
    <!-- 裁剪弹窗 -->
    <el-dialog :append-to-body="true" :visible.sync="cropperModel" v-if="cropperModel" :close-on-press-escape=false width="800px"  @close="beforeClose(cropperFile)">
      <cropper-photo :img-file="cropperFile" ref="vueCropper"  @upload="upload"></cropper-photo>
    </el-dialog>
  </div>
</template>

<script>
// import {getToken} from "@/utils/auth";
import CropperPhoto from './croppers'; //图片裁剪组件
import {uploadIocn} from '@/api/application/appAdd' //图片上传接口
import {generatefileUrl} from '@/api/file'
export default {
  components:{
    CropperPhoto
  },
  data() {
    return {
      //图片列表
      imageList: [

      ],
      imageLists: [],
      //已上传文件字符串
      uploadedFileStr: "",
      //图片预览
      previewImage: false,
      //预览图地址
      previewImageUrl: "",
      //上传是否完成
      uploadComplete: true,
      dialogVisible: false,
      uploadImgUrl: '', // 上传的图片服务器地址
      headers: {
        // Authorization: "Bearer " + getToken(),
      },
      cropperModel: false, // 剪裁组件弹窗开关
      cropperFile: '',
      cropperBlobFile:[],
      uploadReponse:[],
      loading: false,
      imageIds:[]
    };
  },
  props: {
    value: {
      type: String,
      default: "",
    },
    //父组件传递过来的 需要处理 图片列表
    parentImageList: {
      type: String,
      default: ""
    },
    list: {
      type: Array,
      default: ""
    }
    // fixedNumber: {
    //   type: Array,
    //   default: [1,1.5],
    //   // default: function(){
    //   //     return[1,1.5]
    //   // }
    // }
  },
  watch: {
    parentImageList: function (newValue, oldValue) {
      // console.log("newValue", newValue, "--oldValue", oldValue);
      // console.log(newValue.length);
      //转为数组
      if (newValue.length === 0) {
        console.log("点击了新增");
        this.imageList.length = 0;
        this.$refs["multiImageUpload"].clearFiles();
      }
      if (newValue.length > 0) {
        if (newValue === "odd" || newValue === "even") {
          console.log("点击了新增");
          this.imageList.length = 0;
          this.$refs["multiImageUpload"].clearFiles();
        } else {
          let split = newValue.split(",");
          //先清空原有数据
          this.imageList.length = 0;
          if (split != null) {
            for (let i = 0; i < split.length; i++) {
              this.imageList.push({name: i, url: split[i]})
            }
          }
        }
      }
    }
  },
  created() {
    this.initImageList(this.parentImageList);
    if(this.list.length != 0) {
      this.imageList = this.list.map(e => {
        this.imageIds.push(e.id)
        e.url = generatefileUrl(e.url)
        return e
      })
    }
  },
  methods: {
    beforeUploadPicture(file) {
      console.log("上传前" + file);
    },
    // 上传图片时调用 file上传后的文件结果
    uploadProgress(event, file, fileList) {
      // console.log(event, file, fileList);
      // this.uploadComplete = false;
    },
    // 上传图片成功 res = file.response
    uploadSuccess(res, file, fileList) {
      console.log("上传图片成功");
      console.log(res, file, fileList);
      console.log("上传图片成功");
      // this.uploadComplete = true;
      // this.fileChange(fileList);
    },
    // 上传图片出错
    uploadError(err, file, fileList) {
      this.$message.error("上传出错");
    },
    // 移除图片
    handleRemove(file, fileList,) {
      console.log(fileList,"移除图片");
      console.log(file, fileList)
      this.imageIds = this.imageIds.filter(e => e !== file.id)
      // fileList.forEach(imgId => {
      //   this.imageIds.push(imgId.id)
      // })
      console.log(this.imageIds, '移除图片传递的值')
      this.$emit('uploud', this.imageIds)
      this.fileChange(fileList);
      this.imageList = fileList
    },
    handleChange(file,fileList){
      this.cropperFile = ''
      let types = ['image/jpeg','image/jpg','image/png'];
      for (let i = 0; i < fileList.length; i++) {
        // console.log('fileList[i]',fileList[i]);
        const isImage = types.includes(fileList[fileList.length-1].raw.type);
        const isLtSize = fileList[fileList.length-1].raw.size / 1024 / 1024 < 1
        if (!isImage) {
          this.$message.error({
            message: '上传图片只能是 JPG、JPEG、PNG 格式!',
            type: 'error'
          });
          return false;
          this.cropperModel = false
        }
        if (!isLtSize) {
          this.$message.error({
            message:'上传图片大小不能超过 1MB!',
            type: "error"
          });
          return false;
          this.cropperModel = false
        }

        this.cropperModel = true
        this.cropperFile = fileList[fileList.length-1]
        // this.imageList.pop()
        this.imageLists = fileList
        console.log(this.imageLists,'上传类1别')
      }
    },
    // 上传图片
    upload (data,data2) {
      console.log('uploaddata',data2);
      this.loading = true
      let files = new window.File([data], "ps.jpg", {type: 'image/jpeg'}) // myBlob.type 自定义文件名
      const formData = new FormData()
      formData.append('bucketName', 'images')
      formData.append('fileName', data2)
      formData.append('files', files)
      const imageArrayList  = []
      uploadIocn(formData).then(res => {
        console.log('uploadImagess',res);
        this.imageList.push({
          url:  generatefileUrl(res.data[0].pathUrl),
          id: res.data[0].id
        })
        this.imageIds.push(res.data[0].id)
        this.$emit('uploud', this.imageIds)
        this.cropperModel = false
        const response = {response:{code: res.code, data: res.msg}}
        // console.log('response',response);
        this.uploadReponse.push(response)
        // console.log('this.uploadReponse',this.uploadReponse);
        this.fileChange(this.uploadReponse);
        this.$message({
          type: "success",
          message: "上传成功",
        })

        this.loading = false
      }, err => {
        console.log(err);
        this.$message({
          type: "error",
          message: "上传失败",
        });
        this.loading = false
      })
    },
    // 设置photo值
    fileChange(fileList) {
      // console.log("fileChange", fileList);
      let temp_str = '';
      if (fileList.length > 0) {
        //列表有数据
        for (let i = 0; i < fileList.length; i++) {
          // console.log(fileList[i]);
          //判断原有数据还是上传返回的数据
          //原有数据
          // console.log(typeof (fileList[i].response) == "undefined");
          if (typeof (fileList[i].response) == "undefined") {
            if (i === 0) {
              temp_str += fileList[i].url;
            } else {
              // 最终photo的格式是所有已上传的图片的url拼接的字符串(逗号隔开)
              temp_str += ',' + fileList[i].url;
            }
          } else {
            //上传返回数据
            if (fileList[i].response.code === 200) {
              if (i === 0) {
                temp_str += fileList[i].response.data;
              } else {
                // 最终photo的格式是所有已上传的图片的url拼接的字符串(逗号隔开)
                temp_str += ',' + fileList[i].response.data;
              }
            }
          }
        }
        this.uploadedFileStr = temp_str;
      }
      // console.log("temp_str" + temp_str);
      this.sendMsgToParent();
    },
    // 图片预览
    handlePictureCardPreview(file) {
      // console.log('handlePictureCardPreview',file);
      this.previewImageUrl = file.url;
      this.previewImage = true;
    },
    //初始化图片列表 data为字符串 第一次 created, 其他走监听器
    //数组转换为 [{name: 'food.jpg', url: 'https://xxx.cdn.com/xxx.jpg'}]格式
    initImageList(data) {
      // console.log('initImageList',data);
      if (data === "odd" || data === "even") {
        this.imageList.length = 0;
      } else {
        //转为数组
        if (data.length > 0) {
          let split = data.split(",");
          if (split != null) {
            for (let i = 0; i < split.length; i++) {
              this.imageList.push({name: i, url: split[i]})
            }
          }
        } else {
          this.imageList.length = 0;
        }
      }
    },
    //向父组件传值
    sendMsgToParent() {
      this.$emit("getFileListStr", this.uploadedFileStr);
    },
    beforeClose (done) {
      console.log(done,'done')
      // this.imageList.remove(done)
      this.imageList = this.imageLists.filter(e=> e !== done )
      this.cropperModel = false
    },
    aaa(done){
      console.log(done,'done')
      console.log('出发了')
      this.imageList =[]
    }
  }
};
</script>

<style>

</style>

组件cropper.vue文件

<template>
  <div>
    <div class="cropper-content">
      <!-- 剪裁框 -->
      <div class="cropper">
        <vueCropper
          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"
        >
        </vueCropper>
      </div>
      <!-- 预览框 -->
      <div class="show-preview" :style="{'width': '300px', 'height': '300px',  'overflow': 'hidden', 'margin': '0 25px', 'display':'flex', 'align-items' : 'center'}">
        <div :style="previews.div" class="preview">
          <img :src="previews.url" :style="previews.img">
        </div>
      </div>
    </div>
    <div class="footer-btn">
      <!-- 缩放旋转按钮 -->
      <div class="scope-btn">
        <el-button type="primary" icon="el-icon-zoom-in" @click="changeScale(1)">放大</el-button>
        <el-button type="primary" icon="el-icon-zoom-out" @click="changeScale(-1)">缩小</el-button>
        <!-- <el-button type="primary" @click="rotateLeft">逆时针旋转</el-button>
        <el-button type="primary" @click="rotateRight">顺时针旋转</el-button> -->
      </div>
      <!-- 确认上传按钮 -->
      <div class="upload-btn">
        <el-button type="primary" @click="uploadImg('blob')">上传</el-button>
      </div>
    </div>
  </div>
</template>

<script>
import { VueCropper } from 'vue-cropper'
export default {
  components: { VueCropper },
  data () {
    return {
      previews: {}, // 预览数据
      option: {
        img: '', // 裁剪图片的地址  (默认:空)
        outputSize: 1,       //裁剪生成图片的质量(可选0.1 - 1)
        outputType: 'jpeg',  //裁剪生成图片的格式(jpeg || png || webp)
        info: true,          //图片大小信息
        canScale: true,      //图片是否允许滚轮缩放
        autoCrop: true,      //是否默认生成截图框
        autoCropWidth: 300,  //默认生成截图框宽度
        autoCropHeight: 150, //默认生成截图框高度
        fixed: true,         //是否开启截图框宽高固定比例
        fixedNumber: [1.77, 1], //截图框的宽高比例
        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: '400px 150px'  //图片默认渲染方式
      },
      downImg: '#',
      loading: false
    }
  },
  props:['imgFile','fixedNumber'],
  created(){
    this.loading = true
    this.Update()
  },
  methods: {
    changeScale (num) {
      //  console.log("点击了图片缩放");
      // 图片缩放
      num = num || 1
      this.$refs.cropper.changeScale(num)
    },
    rotateLeft () {
      console.log("点击了向左旋转");
      // 向左旋转
      this.$refs.cropper.rotateLeft()
    },
    rotateRight () {
      console.log("点击了向右旋转");
      // 向右旋转
      this.$refs.cropper.rotateRight()
    },
    Update () {
      this.option.img = ''
      console.log('this.imgFile',this.imgFile);
      this.option.img = this.imgFile.url
      this.loading = false
    },
    realTime (data) {
      // 实时预览
      this.previews = data
    },
    uploadImg (type) {
      this.loading = this.$loading({
        lock: true,
        text: "上传中",
        background: "rgba(0, 0, 0, 0.7)",
      });
      // console.log("点击了上传");
      const emitArr = []
      // 将剪裁好的图片回传给父组件
      event.preventDefault()
      let that = this
      if (type === 'blob') {
        this.$refs.cropper.getCropBlob(data => {
          console.log('getCropBlob',data);
          that.$emit('upload', data, this.imgFile.name)
          this.loading.close();
        })
      } else {
        this.$refs.cropper.getCropData(data => {
          // console.log('getCropData',data);
          that.$emit('upload', data, this.imgFile.name)
          this.loading.close();
        })
      }
    }
  }
}
</script>
<style>
.cropper-content {
  display: flex;
  display: -webkit-flex;
  justify-content: flex-end;
  -webkit-justify-content: flex-end;
}
.cropper-content .cropper {
  width: 350px;
  height: 300px;
}
.cropper-content .show-preview {
  flex: 1;
  -webkit-flex: 1;
  display: flex;
  display: -webkit-flex;
  justify-content: center;
  -webkit-justify-content: center;
  overflow: hidden;
  border: 1px solid #cccccc;
  background: #cccccc;
  margin-left: 40px;
}
.preview {
  overflow: hidden;
  border: 1px solid #cccccc;
  background: #cccccc;
}
.footer-btn {
  margin-top: 30px;
  display: flex;
  display: -webkit-flex;
  justify-content: flex-end;
  -webkit-justify-content: flex-end;
}
.footer-btn .scope-btn {
  width: 250px;
  display: flex;
  display: -webkit-flex;
  justify-content: space-between;
  -webkit-justify-content: space-between;
}
.footer-btn .upload-btn {
  flex: 1;
  -webkit-flex: 1;
  display: flex;
  display: -webkit-flex;
  justify-content: center;
  -webkit-justify-content: center;
}
.footer-btn .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;
  margin: 0;
  -webkit-transition: 0.1s;
  transition: 0.1s;
  font-weight: 500;
  padding: 8px 15px;
  font-size: 12px;
  border-radius: 3px;
  color: #fff;
  background-color: #67c23a;
  border-color: #67c23a;
}
</style>

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值