查看实际效果
引用vue-cropper
npm install vue-cropper
yarn 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>