查看实际效果
引用vue-cropper
npm install vue-cropperyarn add vue-cropper
全局引用import VueCropper from 'vue-cropper'Vue.use(VueCropper)直接使用import { VueCropper } from 'vue-cropper'export default { name: 'CropperModal', components: { VueCropper, }, data() { return { } },}</script>
创建组件文件夹
上传按钮组件 index.vue
<template> <div class="ant-upload-preview"> <div style="width: 100%"> <a-upload name="avatar" listType="picture-card" :showUploadList="false" :beforeUpload="beforeUpload" :customRequest="function () {}" @change="handleChange" > <img class="upload_img" v-if="imageUrl" :src="imageUrl" alt="avatar" /> <div v-else> <a-icon :type="loading ? 'loading' : 'plus'" /> <div class="ant-upload-text">上传图片</div> </div> </a-upload> </div> <!-- modal --> <cropper-modal ref="CropperModal" :imgType="imgType" @cropper-no="handleCropperClose" @cropper-ok="handleCropperSuccess" ></cropper-modal> </div></template><script>import CropperModal from './CropperModal'export default { components: { CropperModal, }, props: { //图片裁切配置 options: { type: Object, default: function () { return { autoCrop: true, //是否默认生成截图框 autoCropWidth: 180, //默认生成截图框宽度 autoCropHeight: 180, //默认生成截图框高度 fixedBox: false, //是否固定截图框大小 不允许改变 previewsCircle: true, //预览图是否是原圆形 title: '修改头像', } }, }, // 上传图片的大小,单位M imgSize: { type: Number, default: 2, }, //图片存储在oss上的上级目录名 imgType: { type: String, default: '', }, // 图片地址 imageUrl: { type: String, default: '', }, }, data() { return { loading: false, isStopRun: false, } }, methods: { //从本地选择文件 handleChange(info) { if (this.isStopRun) { return } this.loading = true const { options } = this this.getBase64(info.file.originFileObj, (imageUrl) => { const target = Object.assign({}, options, { img: imageUrl, }) this.$refs.CropperModal.edit(target) }) }, // 上传之前 格式与大小校验 beforeUpload(file) { this.isStopRun = false var fileType = file.type if (fileType.indexOf('image') < 0) { this.$message.warning('请上传图片') this.isStopRun = true return false } const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg' if (!isJpgOrPng) { this.$message.error('你上传图片格式不正确!') this.isStopRun = true } const isLtSize = file.size < this.imgSize * 1024 * 1024 if (!isLtSize) { this.$message.error('图片大小不能超过' + this.imgSize + 'MB!') this.isStopRun = true } return isJpgOrPng && isLtSize }, //获取服务器返回的地址 handleCropperSuccess(data) { //将返回的数据回显 this.loading = false this.$emit('crop-upload-success', data) }, // 取消上传 handleCropperClose() { this.loading = false this.$emit('crop-upload-close') }, getBase64(img, callback) { const reader = new FileReader() reader.addEventListener('load', () => callback(reader.result)) reader.readAsDataURL(img) }, },}</script><style lang="less" scoped>.avatar-upload-wrapper { height: 180px; width: 100%;}.ant-upload-preview { background-color: #fff; .avatar-uploader > .ant-upload { width: 128px; height: 128px; } .ant-upload-select-picture-card i { font-size: 32px; color: #999; } .upload_img { width: 100%; } .ant-upload-select-picture-card .ant-upload-text { margin-top: 8px; color: #666; }}</style>
模态框 CropperModal.vue
<template> <a-modal :visible="visible" :title="options.title" :maskClosable="false" :confirmLoading="confirmLoading" :width="800" @cancel="cancelHandel" > <a-row> <a-col :xs="24" :md="12" :style="{ height: '350px' }"> <vue-cropper ref="cropper" :img="options.img" :info="true" :autoCrop="options.autoCrop" :autoCropWidth="options.autoCropWidth" :autoCropHeight="options.autoCropHeight" :fixedBox="options.fixedBox" @realTime="realTime" > </vue-cropper> </a-col> <a-col :xs="24" :md="12" :style="{ height: '350px' }"> <div :class="options.previewsCircle ? 'avatar-upload-preview' : 'avatar-upload-preview_range'"> <img :src="previews.url" :style="previews.img" /> </div> </a-col> </a-row> <template slot="footer"> <a-button key="back" @click="cancelHandel">取消</a-button> <a-button key="submit" type="primary" :loading="confirmLoading" @click="okHandel">保存</a-button> </template> </a-modal></template><script>import { UpPic } from './index'export default { name: 'CropperModal', data() { return { visible: false, img: null, confirmLoading: false, options: { img: '', //裁剪图片的地址 autoCrop: true, //是否默认生成截图框 autoCropWidth: 180, //默认生成截图框宽度 autoCropHeight: 180, //默认生成截图框高度 fixedBox: true, //是否固定截图框大小 不允许改变 previewsCircle: true, //预览图是否是原圆形 title: '修改头像', }, previews: {}, url: { upload: '/sys/common/saveToImgByStr', }, } }, props: { //图片存储在oss上的上级目录名 imgType: { type: String, default: '', }, }, methods: { edit(record) { const { options } = this this.visible = true this.options = Object.assign({}, options, record) }, /** * 取消截图 */ cancelHandel() { this.confirmLoading = false this.visible = false this.$emit('cropper-no') }, /** * 确认截图 */ okHandel() { const that = this that.confirmLoading = true // 获取截图的base64 数据 this.$refs.cropper.getCropData((data) => { UpPic({ img_type: this.imgType, img_byte: data, }) .then((res) => { that.$emit('cropper-ok', res) }) .catch((err) => { that.$message.error(err) }) .finally(() => { that.cancelHandel() }) }) }, //移动框的事件 realTime(data) { this.previews = data }, },}</script><style lang="less" scoped>.avatar-upload-preview_range,.avatar-upload-preview { position: absolute; top: 50%; transform: translate(50%, -50%); width: 180px; height: 180px; border-radius: 50%; box-shadow: 0 0 4px #ccc; overflow: hidden; img { background-color: red; height: 100%; }}.avatar-upload-preview_range { border-radius: 0;}</style>
ajax网络接口 index.js
import request from '@/utils/request'import qs from 'qs'const Api = { UpPic: '/UpPic',}/** * 上传图片 * @param parameter * @returns {*} */export function UpPic(parameter) { return request({ url: Api.UpPic, method: 'post', data: qs.stringify(parameter) })}
使用组件
<template> <div class="container"> <image-cropper :options="cropperOptions" :imgSize="2" :imgType="imgType" :imageUrl="imgUrl" @crop-upload-close="cropClose" @crop-upload-success="cropSuccess" /> </div></template><script>import ImageCropper from '@/components/ImageCropper'export default { name: 'AddBanner', data() { return { cropperOptions: { autoCrop: true, //是否默认生成截图框 autoCropWidth: 200, //默认生成截图框宽度 autoCropHeight: 200, //默认生成截图框高度 fixedBox: false, //是否固定截图框大小 不允许改变 previewsCircle: false, //预览图是否是圆形 title: '上传广告图片', //模态框上显示的标题 }, imgType: 'testUp', //图片存储在oss上的上级目录名 imgUrl: '', //上传图片所得到的地址 } }, components: { ImageCropper, }, methods: { //上传操作结束 cropClose() { console.log('上传操作结束') }, //上传图片成功 cropSuccess(data) { this.imgUrl = data }, },}</script><style lang="less" scoped>.container { padding-top: 50px; padding-left: 200px; background-color: #fff; min-height: 650px; .a_select { width: 220px; }}</style>