npm install vue-cropper
import VueCropper from 'vue-cropper'
Vue.use(VueCropper)
用户上传图片后,需要裁剪,并保留,上传到服务器
点击上传,从本地选择图片文件
选择文件后弹出模态框(将选择的图片传递过去) 模态框作为裁剪图片的容器
进行裁剪
获取裁剪后的结果 并将裁剪后的图片上传到服务器,返回图片地址给父组件
父组件获取到裁剪后的图片地址后将图片回显
<template>
<div class="ant-upload-preview">
<div style="width: 100%">
<a-upload
name="avatar"
:showUploadList="false"
:beforeUpload="beforeUpload"
:customRequest="function(){}"
@change="handleChange"
>
<a-icon type="cloud-upload-o" class="upload-icon"/>
<div class="mask">
<a-icon type="plus"/>
</div>
<img :src="imageUrl" width="180px" height="180px"/>
</a-upload>
</div>
</div>
<!-- modal -->
<cropper-modal ref="CropperModal" @ok="handleCropperSuccess"></cropper-modal>
</template>
<script>
import CropperModal from './CropperModal'
export default {
components: {
CropperModal
},
props: {
//图片格式
imgFormat: {
type: Array,
default: function() {
return ['image/jpeg']
}
},
//图片大小
imgSize: {
type: Number,
default: 2
},
//图片裁切配置
options: {
type: Object,
default: function() {
return {
autoCropWidth: 180,
autoCropHeight: 180
}
}
},
//回显图片路径
value: {
type: String,
default: ''
}
},
data() {
return {
loading: false,
imageUrl: '',
}
},
watch: {
value: {
handler(val) {
this.imageUrl = val || ''
},
immediate: true
}
},
methods: {
//从本地选择文件
handleChange(info) {
let { options } = this
this.getBase64(info.file.originFileObj, (imageUrl) => {
let target = Object.assign({}, options, {
img: imageUrl
})
this.$refs.CropperModal.edit(target)
})
},
// 上传之前 格式与大小校验
beforeUpload(file) {
var fileType = file.type
if (fileType.indexOf('image') < 0) {
this.$message.warning('请上传图片')
return false
}
},
//裁剪成功后的File对象
handleCropperSuccess(data) {
//进行图片上传动作
// 模拟后端请求 2000 毫秒延迟
let that = this
//将返回的数据回显
that.imageUrl = window._CONFIG['imgDomainURL'] + '/' + data
that.avatar = data
},
getBase64(img, callback) {
const reader = new FileReader()
reader.addEventListener('load', () => callback(reader.result))
reader.readAsDataURL(img)
}
}
}
</script>
<style lang="scss" scoped>
.avatar-upload-wrapper {
height: 180px;
width: 100%;
}
.ant-upload-preview {
position: relative;
margin: 0 auto;
width: 100%;
max-width: 180px;
border-radius: 50%;
box-shadow: 0 0 4px #ccc;
.upload-icon {
position: absolute;
top: 0;
right: 10px;
font-size: 1.4rem;
padding: 0.5rem;
background: rgba(222, 221, 221, 0.7);
border-radius: 50%;
border: 1px solid rgba(0, 0, 0, 0.2);
}
.mask {
opacity: 0;
position: absolute;
background: rgba(0, 0, 0, 0.4);
cursor: pointer;
transition: opacity 0.4s;
&:hover {
opacity: 1;
}
i {
font-size: 2rem;
position: absolute;
top: 50%;
left: 50%;
margin-left: -1rem;
margin-top: -1rem;
color: #d6d6d6;
}
}
img, .mask {
width: 180px;
height: 180px;
border-radius: 50%;
overflow: hidden;
}
}
</style>
<template>
<a-modal
:visible="visible"
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="avatar-upload-preview">
<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 { VueCropper } from 'vue-cropper'
export default {
name: 'cropperModal',
components: {
VueCropper
},
data() {
return {
visible: false,
img: null,
confirmLoading: false,
options: {
img: window._CONFIG['imgDomainURL'] + '/' + Vue.ls.get(USER_INFO).avatar,//裁剪图片的地址
autoCrop: true, //是否默认生成截图框
autoCropWidth: 200, //默认生成截图框宽度
autoCropHeight: 200, //默认生成截图框高度
fixedBox: true //固定截图框大小 不允许改变
},
previews: {},
url:{
upload:'/sys/common/saveToImgByStr'
}
}
},
methods: {
edit(record) {
console.log(record)
let { options } = this
this.visible = true
this.options = Object.assign({}, options, record)
},
cancelHandel() {
this.options = {
img: './avatar2.jpg',
autoCrop: true,
autoCropWidth: 200,
autoCropHeight: 200,
fixedBox: true
}
this.confirmLoading = false
this.visible = false
},
okHandel() {
const that = this
that.confirmLoading = true
// 获取截图的base64 数据
this.$refs.cropper.getCropData((data) => {
var file={
imgByte:data
}
axios({
url:that.url.upload,
method: 'post',
data: file,
headers:{
'Content-Type':'application/json'
}
}).then((res)=>{
that.$emit('ok', res.message)
that.cancelHandel()
})
})
},
//移动框的事件
realTime(data) {
this.previews = data
},
}
}
</script>
<style lang="scss" scoped>
.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 {
width: 100%;
height: 100%;
}
}
</style>