vue-cropper使用问题请教(可以留下联系方式沟通,问题解决了有偿)
因为需要使用到图片裁剪功能,网上找到了vue-cropper,参考了网上的使用教程及示例,自己在copy过程中还是遇到了很多问题,希望能得到指教(刚接触前端开发不到一个月,实属人菜),以下是自己的代码(vue2+TS+ant-design-vue)
目前的问题是:
1.a-upload 组件无法预览后台的图片
2.裁剪框能获取到裁剪后的base64数据,不知道如何转换格式及上传到后台服务器上去
上传按钮组件 index.vue
<template>
<div class="ant-upload-preview">
<div style="width: 500px">
<a-upload
listType="picture-card"
:showUploadList="false"
:beforeUpload="beforeUpload"
:customRequest="function () {}"
@change="handleChange"
@preview="handlePreview"
>
<img
alt="example"
style="width: 100%"
v-if="imageUrl"
:src="previewImage"
/>
<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"
:visible="previewVisible"
@cropper-no="handleCropperClose"
@cropper-ok="handleCropperSuccess"
></cropper-modal>
</div>
</template>
<script lang="ts">
import CropperModal from './CropperModal.vue'
function getBase64(file: any) {
return new Promise((resolve: any, reject: any) => {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => resolve(reader.result)
reader.onerror = (error) => reject(error)
})
}
export default {
components: {
CropperModal
},
props: {
//图片裁切配置
options: {
type: Object,
default: function () {
return {
autoCrop: true, //是否默认生成截图框
autoCropWidth: 280, //默认生成截图框宽度
autoCropHeight: 396, //默认生成截图框高度
fixedBox: true, //是否固定截图框大小 不允许改变
previewsCircle: false, //预览图是否是原圆形
title: '调整图片'
}
}
},
// 上传图片的大小,单位M
imgSize: {
type: Number,
default: 5
},
//图片存储在oss上的上级目录名
imgType: {
type: String,
default: ''
},
// 图片地址
imageUrl: {
type: String,
default: ''
},
previewVisible: {
type: Boolean,
default: false
},
previewImage: {
type: String,
default: ''
}
},
data() {
return {
loading: false,
isStopRun: false
}
},
methods: {
async handlePreview(file: any) {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj)
}
this.previewImage = file.url || file.preview
this.previewVisible = true
},
//从本地选择文件
handleChange(info: any) {
if (this.isStopRun) {
return
}
this.loading = true
const { options } = this
this.getBase64(info.file.originFileObj, (imageUrl: string) => {
const target = Object.assign({}, options, {
img: imageUrl
})
this.$refs.CropperModal.edit(target)
})
},
// 上传之前 格式与大小校验
beforeUpload(file: any) {
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
},
getBase64(img: any, callback: any) {
const reader = new FileReader()
reader.addEventListener('load', () => callback(reader.result))
reader.readAsDataURL(img)
// reader.readAsArrayBuffer(img)
},
//获取服务器返回的地址
handleCropperSuccess(data: any) {
this.loading = false
this.$emit('crop-upload-success', data)
},
// 取消上传
handleCropperClose() {
this.loading = false
this.$emit('crop-upload-close')
}
}
}
</script>
<style lang="less" scoped>
.ant-upload-preview {
background-color: #fff;
border-radius: 8px;
.upload_img {
width: 100%;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
}
.list-upload {
/deep/ .ant-upload-list-item-name {
width: unset;
}
/deep/ .ant-upload-list-item-card-actions {
position: relative;
right: 0;
margin-left: 11px;
}
/deep/ .ant-upload-list {
line-height: 1;
}
}
</style>
模态框 CropperModal.vue
<template>
<a-modal
:visible="visible"
:title="options.title"
:maskClosable="false"
:confirmLoading="confirmLoading"
:width="1000"
@cancel="cancelHandel"
>
<a-row>
<a-col
:xs="24"
:md="12"
:style="{ height: '450px' }"
>
<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 lang="ts">
// import { UpPic } from './index.js'
export default {
name: 'CropperModal',
components: {},
data() {
return {
visible: false,
img: null,
confirmLoading: false,
options: {
img: '', //裁剪图片的地址
autoCrop: false, //是否默认生成截图框
autoCropWidth: 280, //默认生成截图框宽度
autoCropHeight: 396, //默认生成截图框高度
fixedBox: true, //是否固定截图框大小 不允许改变
previewsCircle: false, //预览图是否是原圆形
centerBox: true, //截图框是否被限制在图片里面
title: '调整图片'
},
previews: {},
url: {
upload: 'xxxxxxx'
}
}
},
props: {
//图片存储在oss上的上级目录名
imgType: {
type: String,
default: ''
}
},
methods: {
edit(record: any) {
const { options } = this
this.visible = true
this.options = Object.assign({}, options, record)
},
/**
* 确认截图
*/
okHandel() {
const that = this
that.confirmLoading = true
// 获取截图的base64 数据
this.$refs.cropper.getCropData((data: any) => {
//将裁剪后的图片对象给**父组件**,然后关闭对话框
that.$emit('cropper-ok', data)
that.cancelHandel()
})
},
/**
* 取消截图
*/
cancelHandel() {
this.confirmLoading = false
this.visible = false
this.$emit('cropper-no')
},
//移动框的事件
realTime(data: any) {
this.previews = data
}
}
}
</script>
<style lang="less" scoped>
.avatar-upload-preview_range,
.avatar-upload-preview {
position: absolute;
top: 65%;
transform: translate(50%, -50%);
width: 280px;
height: 396px;
box-shadow: 0 0 4px #ccc;
overflow: hidden;
img {
background-color: red;
height: 100%;
}
}
.avatar-upload-preview_range {
border-radius: 0px;
}
</style>
使用组件的主页面(裁剪框部分)
<template>
<div class="container">
<image-cropper
:options="cropperOptions"
:imgSize="5"
:imgType="imgType"
:imageUrl="imgUrl"
@crop-upload-close="cropClose"
@crop-upload-success="cropSuccess"
/>
</div>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
import ImageCropper from '@/components/ImageCropper'
import { VueCropper } from 'vue-cropper'
@Component({
components: {
ImageCropper,
VueCropper
}
})
export default class courseCenter extends Vue {
//===================================data区域begin
name: any = 'AddBanner'
cropperOptions: any = {
autoCrop: true, //是否默认生成截图框
autoCropWidth: 280, //默认生成截图框宽度
autoCropHeight: 396, //默认生成截图框高度
fixedBox: true, //是否固定截图框大小 不允许改变
previewsCircle: false, //预览图是否是圆形
title: '调整图片' //模态框上显示的标题
}
imgType: any = 'testUp' //图片存储在oss上的上级目录名
imgUrl: any = '' //上传图片所得到的地址
previewImage: string = ''
previewVisible: boolean = false
//===================================data区域end
//===================================computed区域begin
//===================================computed区域end
//===================================methods区域begin
//上传操作结束
cropClose() {
console.log('上传操作结束')
}
//上传图片成功
cropSuccess(data: any) {
console.log(data)
this.imgUrl = data
console.log(data.url)
}
handleOk() {
this.confirmLoading = true
setTimeout(() => {
this.formDialogVisible = false
this.confirmLoading = false
}, 2000)
}
handleCancel() {
this.formDialogVisible = false
this.$nextTick(function () {
;(this.$refs.formRef as any).resetFields()
})
this.fileList = []
this.form = formHelper.copyNewForm(formHelper.form)
}
handleFileCancel() {
this.previewVisible = false
}
//===================================methods区域end
mounted() {}
created() {}
</script>
<style lang="scss" scoped>
@import '../../assets/css/Course/home.scss';
/deep/ .ant-form-item-control {
line-height: 36px;
}
.create-course /deep/ .ant-modal-footer {
padding: 18px 22px 18px 0px !important;
}
</style>