使用cropper截取功能,并且设置比例

上传组件及展示,(可简历建立vue文件直接赋值)

<template>

  <div>

    <div class="uploadWrap">

      <el-upload

        class="avatar-uploader"

        action="#"

        :http-request="uploadFileFunc"

        :before-upload="beforeAvatarUpload"

        :disabled="uploadImgTchDisabled"

        :show-file-list="false"

        accept=".jpg, .jpeg, .png, .PNG"

      >

        <div class="avatar-uploader-icon">

          <i class="el-icon-plus" />

        </div>

      </el-upload>

      <div

        v-for="(item, index) in imgUrlList"

        v-show="imgUrlList.length > 0"

        :key="index"

        @click="selectImg(item)"

      >

        <div v-if="index===0" class="coverimg" :class="{ selectedItem: item === bindVal }">

          <img class="img_size" :src="item" :style="{ 'object-fit': mode }">

          <span v-if="imgUrlList.length - index > imgList.length" class="delWrap">

            <div class="delBox" @click.stop="handleRemove(index)">

              <i class="el-icon-delete" />

            </div>

          </span>

        </div>

      </div>

    </div>

    <ImgCropper

      :img-url="originalImg"

      :ratio="ratio"

      :width="ratio[0]"

      :height="ratio[1]"

      :show.sync="showCropper"

      @success="success"

    />

  </div>

</template>

<script>

import mixin from '@/mixin/two-ways'

import { uploadImg } from '@/api/common'

export default {

  name: 'ImgTemplate',

  mixins: [mixin()],

  props: {

    imgList: {

      type: Array,

      default: () => []

    },

    mode: {

      type: String,

      default: 'cover'

    },

    ratio: {

      type: Array,

      default: () => [750, 1334]

    },

    // 是否需要裁剪

    isCut: {

      type: Boolean,

      default: true

    }

  },

  data() {

    return {

      imgUrlList: [],

      originalImg: '',

      showCropper: false,

      uploadImgTchDisabled: false

    }

  },

  watch: {

    imgList() {

      this.imgUrlList = Object.assign([], this.imgList)

    }

  },

  methods: {

    handleRemove(index) {

      this.imgUrlList.splice(index, 1)

      this.bindVal = this.imgUrlList[0]

    },

    getObj() {

      return { backgroundImg: this.planTotalObj.m1 }

    },

    selectImg(item) {

      this.bindVal = item

    },

    success({ blob }) {

      this.handleTchBeforeUpload(blob)

    },

    handleLimit(file, fileList) {

      if (fileList.length >= 1) {

        this.disabled = true

      } else {

        this.disabled = false

      }

      this.$forceUpdate()

    },

    uploadFileFunc(file) {

      if (!this.isCut) {

        this.handleTchBeforeUpload(file.file)

      }

    },

    beforeAvatarUpload(file) {

      var hase = file.name.lastIndexOf('.')

      var hasetype = file.name.substr(hase).toLowerCase()

      const isJPEG = hasetype === '.jpeg'

      const isJPG = hasetype === '.jpg'

      const isGIF = hasetype === '.gif'

      const isPNG = hasetype === '.png'

      if (!isJPG && !isJPEG && !isGIF && !isPNG) {

        this.$message({

          message: '上传图片格式不正确!',

          type: 'error'

        })

      }

      if (this.isCut) {

        this.originalImg = window.URL.createObjectURL(new Blob([file]))

        this.showCropper = true

      }

      const result = isJPG || isJPEG || isGIF || isPNG

      return result

    },

    handleTchBeforeUpload(file) {

      const formData = new FormData() // formdata格式

      // 追加文件的名字

      formData.append('imageFile', file)

      this.uploadImgTchDisabled = true

      const loading = this.$loading({

        lock: true,

        text: '图片上传中...',

        spinner: 'el-icon-loading',

        background: 'rgba(0, 0, 0, 0.7)'

      })

      uploadImg(formData)

        .then(res => {

          loading.close()

          this.uploadImgTchDisabled = false

          if (res.successful && res.rt) {

            this.imgUrlList.unshift(res.rt.oSSFileDto.path)

            this.bindVal = res.rt.oSSFileDto.path

          }

        })

        .catch(() => {

          loading.close()

          this.uploadImgTchDisabled = false

        })

    }

  }

}

</script>

<style scoped lang="scss">

::v-deep .avatar-uploader {

  height: 110px;

  width: 110px;

  border-radius: 4px;

  margin: 0 12px 12px 0;

  border-radius: 4px;

  .el-upload {

    background: rgba(255, 255, 255, 0.2);

    border-radius: 4px;

  }

  .el-upload:hover {

    border-color: #409eff;

  }

  .avatar-uploader-icon {

    color: #fff;

    width: 110px;

    height: 110px;

    display: flex;

    align-items: center;

    justify-content: center;

    .el-icon-plus {

      font-size: 30px;

    }

  }

  .avatar {

    width: 100%;

    height: 100%;

    display: block;

  }

}

.uploadWrap {

  display: flex;

  align-items: center;

  flex-wrap: wrap;

  .delWrap {

    z-index: 101;

    position: absolute;

    width: 100%;

    height: 100%;

    right: 0;

    top: 0;

    cursor: pointer;

    text-align: center;

    color: #fff;

    opacity: 0;

    font-size: 20px;

    transition: opacity 0.3s;

    &:hover {

      opacity: 10;

    }

    .delBox {

      position: absolute;

      right: 0;

      width: 28px;

      height: 28px;

      display: flex;

      align-items: center;

      justify-content: center;

      opacity: 0.4;

      background: #07164d;

      border-radius: 0 4px 0 4px;

      -webkit-transition: all 0.3s ease-in;

      -moz-transition: all 0.3s ease-in;

      transition: all 0.3s ease-in;

      .el-icon-delete {

        margin-left: 2px;

        margin-bottom: 2px;

        cursor: pointer;

        font-size: 16px;

      }

    }

  }

  .selectedItem {

    position: relative;

    border: 3px solid #11fefd !important;

    transform: scale(1.02);

    &::before {

      content: '';

      position: absolute;

      left: -1px;

      top: -1px;

      width: 16px;

      height: 16px;

      background: url('//image.g2s.cn/zhs_yanfa_150820/ablecommons/demo/202207/d9a8a6b0241f478693e0133adf8245c1.png');

      background-size: cover;

      image-rendering: -moz-crisp-edges; /* Firefox */

      image-rendering: -o-crisp-edges; /* Opera */

      image-rendering: -webkit-optimize-contrast; /*Webkit (non-standard naming) */

      image-rendering: crisp-edges;

      -ms-interpolation-mode: nearest-neighbor; /* IE (non-standard property) */

    }

  }

  .coverimg {

    position: relative;

    cursor: pointer;

    width: 110px;

    height: 110px;

    background-repeat: no-repeat;

    background-size: 100% 100%;

    margin: 0 12px 12px 0;

    border-radius: 4px;

    border: 1px solid rgba(29, 95, 133, 1);

    .img_size {

      width: 100%;

      height: 100%;

    }

  }

}

::v-deep .hiddenUpload .el-upload.el-upload--picture-card {

  display: none !important;

}

::v-deep .hiddenUpload .el-button--success.is-plain {

  display: none !important;

}

</style>

截图组件,前提是学会看之前的双向书库绑定

<template>

  <el-dialog title="照片裁剪" :visible.sync="syncShow" width="650px" append-to-body>

    <div style="width: 100%; height: 500px">

      <vue-cropper

        ref="cropper"

        auto-crop

        :fixed="fixed"

        :img="imgUrl"

        :auto-crop-width="width"

        info-true

        output-type="png"

        :auto-crop-height="height"

        :fixed-number="ratio"

        :center-box="false"

      />

    </div>

    <span slot="footer" class="dialog-footer">

      <div class="vue-cropper-operation fl">

        <el-button

          type="primary"

          size="mini"

          @click="$refs.cropper.changeScale(1)"

        >放大</el-button>

        <el-button

          type="primary"

          size="mini"

          @click="$refs.cropper.changeScale(-1)"

        >缩小</el-button>

        <el-button

          type="primary"

          size="mini"

          @click="$refs.cropper.rotateLeft()"

        >左旋转</el-button>

        <el-button

          type="primary"

          size="mini"

          @click="$refs.cropper.rotateRight()"

        >右旋转</el-button>

      </div>

      <el-button @click="syncShow = false">取 消</el-button>

      <el-button type="primary" @click="confirm">确 定</el-button>

    </span>

  </el-dialog>

</template>

<script>

import twoWaysSyncMixin from '@/mixin/two-ways-sync'

import { VueCropper } from 'vue-cropper'

export default {

  name: 'ImgCropper',

  components: {

    VueCropper

  },

  mixins: [

    twoWaysSyncMixin({

      show: {

        type: Boolean,

        default: false

      }

    })

  ],

  props: {

    // 裁剪图片地址

    imgUrl: {

      type: [String, Blob],

      required: false,

      default: ''

    },

    // 裁剪图片宽度

    width: {

      type: Number,

      default: 280

    },

    // 裁剪图片高

    height: {

      type: Number,

      default: 280

    },

    // 宽高比

    ratio: {

      type: Array,

      default: () => [9, 16]

    },

    // 固定宽高比

    fixed: {

      type: Boolean,

      default: true

    },

    // 自动上传

    autoUpload: {

      type: Boolean,

      default: false

    },

    // 获取数据类型

    fetchType: {

      type: String,

      default: 'blob',

      validator(value) {

        const valid = ['blob', 'base64'].includes(value)

        return valid

      }

    }

  },

  methods: {

    confirm() {

      const obj = {

        blob: 'getCropBlob',

        base64: 'getCropData'

      }

      // 获取截图数据

      this.$refs.cropper[obj[this.fetchType]]((data) => {

        this.syncShow = false

        this.handleSuccess(data)

      })

    },

    // 处理成功回调

    handleSuccess(blob) {

      this.$emit('success', {

        blob

      })

    }

  }

}

</script>

<style lang="scss" scoped></style>

在哪个页面使用直接引入

<ImgTemplate

              v-model="ruleForm.bannerFileUrl"

              :ratio="[750, 750]"

            />

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值