<template>
|
<div class="cropper-wrapper">
|
<div v-if="isView">
|
<el-image :src="imageUrl" class="view-image">
|
<div slot="error" class="image-slot no-cursor">
|
<i class="el-icon-picture-outline"></i>
|
</div>
|
</el-image>
|
</div>
|
<div v-else>
|
<template v-if="!isPreview">
|
<!-- element 上传图片按钮 -->
|
<el-upload
|
class="avatar-uploader"
|
action=""
|
drag
|
:auto-upload="false"
|
:show-file-list="false"
|
:on-change="handleChangeUpload"
|
>
|
<i class="el-icon-plus avatar-uploader-icon"></i>
|
</el-upload>
|
</template>
|
<div class="pre-box" v-else>
|
<el-image :src="previewImg" alt="" class="view-image" />
|
<el-upload
|
class="upload-demo"
|
action=""
|
:auto-upload="false"
|
:show-file-list="false"
|
:on-change="handleChangeUpload"
|
>
|
<el-button v-if="!isView" type="primary" plain>更换图片</el-button>
|
</el-upload>
|
</div>
|
</div>
|
<!-- vueCropper 剪裁图片实现-->
|
<el-dialog title="图片剪裁" :visible.sync="dialogVisible" class="crop-dialog" append-to-body>
|
<div class="cropper-content">
|
<div class="cropper" style="text-align: center">
|
<vueCropper
|
ref="cropper"
|
:img="option.img"
|
:outputSize="option.size"
|
:outputType="option.outputType"
|
:info="true"
|
:full="option.full"
|
:canMove="option.canMove"
|
:canMoveBox="option.canMoveBox"
|
:original="option.original"
|
:autoCrop="option.autoCrop"
|
:fixed="option.fixed"
|
:fixedNumber="option.fixedNumber"
|
:centerBox="option.centerBox"
|
:infoTrue="option.infoTrue"
|
:fixedBox="option.fixedBox"
|
:autoCropWidth="option.autoCropWidth"
|
:autoCropHeight="option.autoCropHeight"
|
@cropMoving="cropMoving"
|
/>
|
</div>
|
</div>
|
<div class="action-box">
|
<el-upload
|
class="upload-demo"
|
action=""
|
:auto-upload="false"
|
:show-file-list="false"
|
:on-change="handleChangeUpload"
|
>
|
<el-button type="primary" plain>更换图片</el-button>
|
</el-upload>
|
<el-button type="primary" plain @click="clearImgHandle">清除图片</el-button>
|
<el-button type="primary" plain @click="rotateLeftHandle">左旋转</el-button>
|
<el-button type="primary" plain @click="rotateRightHandle">右旋转</el-button>
|
<el-button type="primary" plain @click="changeScaleHandle(1)">放大</el-button>
|
<el-button type="primary" plain @click="changeScaleHandle(-1)">缩小</el-button>
|
<el-button type="primary" plain @click="downloadHandle('blob')">下载</el-button>
|
</div>
|
<div slot="footer" class="dialog-footer">
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
<el-button type="primary" @click="finish" :loading="loading">确认</el-button>
|
</div>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script>
|
export default {
|
name: "CropperV",
|
props: {
|
isView: {
|
type: Boolean,
|
default: false
|
},
|
imageUrl: {
|
type: String,
|
default: ""
|
}
|
},
|
data() {
|
return {
|
isPreview: false,
|
dialogVisible: false,
|
previewImg: "", // 预览图片地址
|
// 裁剪组件的基础配置option
|
option: {
|
img: "https://pic1.zhimg.com/80/v2-366c0aeae2b4050fa2fcbfc09c74aad4_720w.jpg", // 裁剪图片的地址
|
info: true, // 裁剪框的大小信息
|
outputSize: 1, // 裁剪生成图片的质量
|
outputType: "png", // 裁剪生成图片的格式
|
canScale: true, // 图片是否允许滚轮缩放
|
autoCrop: true, // 是否默认生成截图框
|
canMoveBox: true, // 截图框能否拖动
|
autoCropWidth: 200, // 默认生成截图框宽度
|
autoCropHeight: 200, // 默认生成截图框高度
|
fixedBox: false, // 固定截图框大小 不允许改变
|
fixed: true, // 是否开启截图框宽高固定比例
|
fixedNumber: [1, 1], // 截图框的宽高比例
|
full: false, // 是否输出原图比例的截图
|
original: false, // 上传图片按照原始比例渲染
|
centerBox: false, // 截图框是否被限制在图片里面
|
infoTrue: true // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
|
},
|
// 防止重复提交
|
loading: false,
|
fileName: ""
|
}
|
},
|
computed: {
|
myIsView() {
|
return this.isView
|
}
|
},
|
watch: {
|
myIsView() {
|
this.setImgMethods()
|
}
|
},
|
mounted() {
|
console.log(this.imageUrl)
|
this.setImgMethods()
|
},
|
methods: {
|
// 设置上传/更换图片显示方法
|
setImgMethods() {
|
if (!this.isView && this.imageUrl?.length > 0) {
|
this.isPreview = true
|
this.previewImg = this.imageUrl
|
} else {
|
this.isPreview = false
|
}
|
},
|
// 上传按钮 限制图片大小和类型
|
handleChangeUpload(file, fileList) {
|
const isJPG = file.raw.type === "image/jpeg" || file.raw.type === "image/png"
|
const isLt2M = file.size / 1024 / 1024 < 2
|
if (!isJPG) {
|
this.$message.error("上传头像图片只能是 JPG/PNG 格式!")
|
return false
|
}
|
if (!isLt2M) {
|
this.$message.error("上传头像图片大小不能超过 2MB!")
|
return false
|
}
|
console.log(file, fileList)
|
this.fileName = file.name
|
// 上传成功后将图片地址赋值给裁剪框显示图片
|
this.$nextTick(async () => {
|
// base64方式
|
// this.option.img = await fileByBase64(file.raw)
|
this.option.img = URL.createObjectURL(file.raw)
|
this.loading = false
|
this.dialogVisible = true
|
})
|
},
|
// 放大/缩小
|
changeScaleHandle(num) {
|
num = num || 1
|
this.$refs.cropper.changeScale(num)
|
},
|
// 左旋转
|
rotateLeftHandle() {
|
this.$refs.cropper.rotateLeft()
|
},
|
// 右旋转
|
rotateRightHandle() {
|
this.$refs.cropper.rotateRight()
|
},
|
// 下载
|
downloadHandle(type) {
|
let aLink = document.createElement("a")
|
aLink.download = "author-img"
|
if (type === "blob") {
|
this.$refs.cropper.getCropBlob((data) => {
|
aLink.href = URL.createObjectURL(data)
|
aLink.click()
|
})
|
} else {
|
this.$refs.cropper.getCropData((data) => {
|
aLink.href = data
|
aLink.click()
|
})
|
}
|
},
|
// 清理图片
|
clearImgHandle() {
|
this.option.img = ""
|
},
|
// 截图框移动回调函数
|
cropMoving(data) {
|
console.log(data)
|
// 截图框的左上角 x,y和右下角坐标x,y
|
// let cropAxis = [data.axis.x1, data.axis.y1, data.axis.x2, data.axis.y2]
|
// console.log(cropAxis)
|
},
|
finish() {
|
// 获取截图的 blob 数据
|
this.$refs.cropper.getCropBlob((blob) => {
|
this.loading = true
|
this.dialogVisible = false
|
this.previewImg = URL.createObjectURL(blob)
|
this.isPreview = true
|
// blob转file
|
let file = new File([blob], this.fileName, { type: blob.type })
|
// file转formData
|
let formData = new FormData()
|
formData.append("files", file)
|
this.$emit("getImageData", formData)
|
})
|
// 获取截图的 base64 数据
|
// this.$refs.cropper.getCropData(data => {
|
// console.log(data)
|
// })
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
.cropper-wrapper {
|
.avatar-uploader .el-upload:hover {
|
border-color: #409eff;
|
}
|
.avatar-uploader-icon {
|
font-size: 28px;
|
color: #8c939d;
|
width: 178px;
|
height: 178px;
|
line-height: 178px;
|
text-align: center;
|
}
|
.avatar {
|
width: 178px;
|
height: 178px;
|
display: block;
|
}
|
.view-image {
|
width: 180px;
|
height: 180px;
|
background: #f5f7fa;
|
font-size: 30px;
|
text-align: center;
|
line-height: 180px;
|
}
|
.image-slot {
|
color: #909399;
|
text-align: center;
|
}
|
}
|
::v-deep {
|
.el-upload-dragger {
|
width: 180px;
|
height: 180px;
|
}
|
}
|
.avatar-uploader .el-upload {
|
border: 1px dashed #d9d9d9;
|
border-radius: 6px;
|
cursor: pointer;
|
position: relative;
|
overflow: hidden;
|
width: 178px;
|
height: 178px;
|
}
|
|
.crop-dialog {
|
.cropper-content {
|
padding: 0 40px;
|
|
.cropper {
|
width: auto;
|
height: 350px;
|
}
|
}
|
|
.action-box {
|
padding: 25px 40px 10px;
|
display: flex;
|
justify-content: center;
|
|
button {
|
width: 80px;
|
margin-right: 15px;
|
}
|
}
|
}
|
</style>
|