高效实现需求的办法,就是防止反复造轮子。图片裁剪的插件也不少,这里我抉择 vue-cropper,起因是功能强大、简略易上手。话不多说,上效果图:

效果图

装置

npm install vue-cropper

应用

import { VueCropper } from 'vue-cropper'

代码实现

以 element-ui + vue-cropper 为例实现头像裁剪

src/App.vue

<template>  <div>    <el-button @click="dialogVisible = true">上传头像</el-button>    <avatar-cropper :dialogVisible.sync="dialogVisible" @closeAvatarDialog="closeAvatarDialog"></avatar-cropper>  </div></template><script>  import avatarCropper from '@/components/avatarCropper'  export default {    components: {      avatarCropper    },    data() {      return {        dialogVisible: false      }    },    methods: {      closeAvatarDialog(data) {    console.log(data)        this.dialogVisible = false      }    }  }</script>

src/components/avatarCropper.vue

<template>  <el-dialog    title="裁剪头像"    :visible.sync="dialogVisible"    :show-close="false"    :close-on-click-modal="false"    :close-on-press-escape="false"    @close="closeDialog"    width="600px"  >    <div class="avatar-container">      <!-- 待上传图片 -->      <div v-show="!options.img">        <el-upload          class="upload"          ref="upload"          action=""          :on-change="upload"          accept="image/png, image/jpeg, image/jpg"          :show-file-list="false"          :auto-upload="false"        >          <el-button slot="trigger" size="small" type="primary" ref="uploadBtn">            抉择图片          </el-button>        </el-upload>        <div>反对jpg、png格局的图片,大小不超过5M</div>      </div>      <!-- 已上传图片 -->      <div v-show="options.img" class="avatar-crop">        <vueCropper          v-if="dialogVisible"          class="crop-box"          ref="cropper"          :img="options.img"          :autoCrop="options.autoCrop"          :fixedBox="options.fixedBox"          :canMoveBox="options.canMoveBox"          :autoCropWidth="options.autoCropWidth"          :autoCropHeight="options.autoCropHeight"          :centerBox="options.centerBox"          :fixed="options.fixed"          :fixedNumber="options.fixedNumber"          :canMove="options.canMove"          :canScale="options.canScale"        ></vueCropper>      </div>    </div>    <span slot="footer" class="dialog-footer">      <div class="reupload" @click="reupload">        <span v-show="options.img">从新上传</span>      </div>      <div>        <el-button @click="closeDialog">取 消</el-button>        <el-button type="primary" @click="getCrop">确 定</el-button>      </div>    </span>  </el-dialog></template><script>import { VueCropper } from 'vue-cropper'export default {  components: {    VueCropper  },  name: 'avatarCropper',  props: {    dialogVisible: {      type: Boolean,      default: false    }  },  data() {    return {      // vueCropper组件 裁剪配置信息      options: {        img: '', // 原图文件        autoCrop: true, // 默认生成截图框        fixedBox: false, // 固定截图框大小        canMoveBox: true, // 截图框能够拖动        autoCropWidth: 200, // 截图框宽度        autoCropHeight: 200, // 截图框高度        fixed: true, // 截图框宽高固定比例        fixedNumber: [1, 1], // 截图框的宽高比例        centerBox: true, // 截图框被限度在图片外面        canMove: false, // 上传图片不容许拖动        canScale: false // 上传图片不容许滚轮缩放      }    }  },  methods: {    // 读取原图    upload(file) {      const isIMAGE = file.raw.type === 'image/jpeg' || file.raw.type === 'image/png'      const isLt5M = file.raw.size / 1024 / 1024 < 5      if (!isIMAGE) {        this.$message({          showClose: true,          message: '请抉择 jpg、png 格局的图片',          type: 'warning'        })        return false      }      if (!isLt5M) {        this.$message({          showClose: true,          message: '图片大小不能超过 5MB',          type: 'warning'        })        return false      }      let reader = new FileReader()      reader.readAsDataURL(file.raw)      reader.onload = e => {        this.options.img = e.target.result // base64      }    },    // 获取截图信息    getCrop() {      // 获取截图的 base64 数据      // this.$refs.cropper.getCropData((data) => {      //   this.$emit('closeAvatarDialog', data)      //   this.closeDialog()      // });      // 获取截图的 blob 数据      this.$refs.cropper.getCropBlob(data => {        this.$emit('closeAvatarDialog', data)        this.closeDialog()      })    },    // 从新上传    reupload() {      this.$refs.uploadBtn.$el.click()    },    // 敞开弹框    closeDialog() {      this.$emit('update:dialogVisible', false)      this.options.img = ''    }  }}</script><style lang="scss" scoped>.dialog-footer {  display: flex;  justify-content: space-between;  align-items: center;  font-size: 14px;  .reupload {    color: #409eff;    cursor: pointer;  }}.avatar-container {  display: flex;  justify-content: center;  align-items: center;  width: 560px;  height: 400px;  background-color: #f0f2f5;  margin-right: 10px;  border-radius: 4px;  .upload {    text-align: center;    margin-bottom: 24px;  }  .avatar-crop {    width: 560px;    height: 400px;    position: relative;    .crop-box {      width: 100%;      height: 100%;      border-radius: 4px;      overflow: hidden;    }  }}</style>

总结

裁剪实现之后能够获取到 base64 和 blob 数据,而后上传至后端。vue-cropper 还有泛滥属性和办法,用起来都很不便,有趣味的同学能够实现一下实时预览。

文档地址:https://github.com/xyxiao001/...


看完不要忘了点个赞呦,据说点赞的来年升职加薪,恋情事业双丰收