上传文件时候接到一个需求 商品必须为固定尺寸 在网上找的 基本在 before-upload 加限制条件没有根本的解决问题 于是想到裁剪后上传
之前上传文件的标签
<el-upload
class="avatar-uploader"
:headers="uploadHeaders"
:action="uploadUrl + '?updateSupport=' + 0"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
<template #tip>
<div class="el-upload__tip">可上传一张图片,140*140</div>
</template>
</el-upload>
参考其他人想要实现自定义上传 需要修改 auto-upload:false http-request 自定义上传方法等
后来发现没有那么麻烦 仅保留before-upload即可
<el-upload
class="avatar-uploader"
:action="''"
:show-file-list="false"
:before-upload="beforeAvatarUpload"
>
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
<template #tip>
<div class="el-upload__tip">可上传一张图片,140*140</div>
</template>
</el-upload>
裁剪工具为 VueCropper
- 安装
npm install vue-cropper // npm 安装
- 局部引入并编写组件 (参考其他小伙伴进行修改)
<template>
<div>
<el-dialog
title="图片剪裁"
v-model="dialogVisiblex"
:close-on-press-escape="false"
:close-on-click-modal="false"
append-to-body
width="1000px"
>
<div class="cropper-content">
<div class="cropper" style="text-align:center">
<vueCropper
ref="cropper"
:img="option.img"
:outputSize="option.outputSize"
:outputType="option.outputType"
:info="option.info"
:canScale="option.canScale"
:autoCrop="option.autoCrop"
:autoCropWidth="option.autoCropWidth"
:autoCropHeight="option.autoCropHeight"
:fixedBox="option.fixedBox"
:fixed="option.fixed"
:fixedNumber="option.fixedNumber"
:canMove="option.canMove"
:canMoveBox="option.canMoveBox"
:original="option.original"
:centerBox="option.centerBox"
:infoTrue="option.infoTrue"
:full="option.full"
:enlarge="option.enlarge"
:mode="option.mode"
>
</vueCropper>
</div>
</div>
<template #footer class="dialog-footer">
<el-button @click="dialogVisiblex = false">取消</el-button>
<el-button type="primary" @click="finish" :loading="loading"
>确认</el-button
>
</template>
</el-dialog>
</div>
</template>
<script>
import VueCropper from "vue-cropper/src/vue-cropper.vue"
export default {
components: {VueCropper},
props: {},
data() {
return {
dialogVisiblex: false,
loading: false,
option: {
img: '', // 裁剪图片的地址 url 地址, base64, blob
outputSize: 1, // 裁剪生成图片的质量
outputType: 'jpeg', // 裁剪生成图片的格式 jpeg, png, webp
info: true, // 裁剪框的大小信息
canScale: true, // 图片是否允许滚轮缩放
autoCrop: true, // 是否默认生成截图框
autoCropWidth: 345, // 默认生成截图框宽度
autoCropHeight: 245, // 默认生成截图框高度
fixedBox: true, // 固定截图框大小 不允许改变
fixed: true, // 是否开启截图框宽高固定比例
fixedNumber: [1, 1], // 截图框的宽高比例 [ 宽度 , 高度 ]
canMove: true, // 上传图片是否可以移动
canMoveBox: true, // 截图框能否拖动
original: false, // 上传图片按照原始比例渲染
centerBox: true, // 截图框是否被限制在图片里面
infoTrue: true, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
full: true, // 是否输出原图比例的截图
enlarge: '1', // 图片根据截图框输出比例倍数
mode: 'contain' // 图片默认渲染方式 contain , cover, 100px, 100% auto
},
unimgurl: '',
success: () => {} // 回调方法
}
},
computed: {},
watch: {},
created() {
},
mounted() {},
activated() {},
methods: {
showModal(obj) {
if (obj.img) {
this.option.img = obj.img
}
//裁剪生成图片的质量
if (obj.outputSize) {
this.option.outputSize = obj.outputSize
} else {
this.option.outputSize = 1
}
//裁剪生成图片的格式
if (obj.outputType) {
this.option.outputType = obj.outputType
} else {
this.option.outputType = 'jpeg'
}
//裁剪框的大小信息
if (obj.info) {
this.option.info = obj.info
} else {
this.option.info = true
}
//图片是否允许滚轮缩放
if (obj.canScale) {
this.option.canScale = obj.canScale
} else {
this.option.canScale = true
}
//是否默认生成截图框
if (obj.autoCrop) {
this.option.autoCrop = obj.autoCrop
} else {
this.option.autoCrop = true
}
//默认生成截图框宽度
if (obj.autoCropWidth) {
this.option.autoCropWidth = obj.autoCropWidth
} else {
this.option.autoCropWidth = 375
}
//默认生成截图框高度
if (obj.autoCropHeight) {
this.option.autoCropHeight = obj.autoCropHeight
} else {
this.option.autoCropHeight = 245
}
//固定截图框大小 不允许改变
if (obj.fixedBox) {
this.option.fixedBox = obj.fixedBox
} else {
this.option.fixedBox = false
}
//是否开启截图框宽高固定比例
if (obj.fixed) {
this.option.fixed = obj.fixed
} else {
this.option.fixed = true
}
//截图框的宽高比例
if (obj.fixedNumber) {
this.option.fixedNumber = obj.fixedNumber
} else {
this.option.fixedNumber = [this.option.autoCropWidth, this.option.autoCropHeight]
}
//上传图片是否可以移动
if (obj.canMove) {
this.option.canMove = obj.canMove
} else {
this.option.canMove = true
}
//截图框能否拖动
if (obj.canMoveBox) {
this.option.canMoveBox = obj.canMoveBox
} else {
this.option.canMoveBox = true
}
//上传图片按照原始比例渲染
if (obj.original) {
this.option.original = obj.original
} else {
this.option.original = false
}
//截图框是否被限制在图片里面
if (obj.centerBox) {
this.option.centerBox = obj.centerBox
} else {
this.option.centerBox = true
}
//true 为展示真实输出图片宽高 false 展示看到的截图框宽高
if (obj.infoTrue) {
this.option.infoTrue = obj.infoTrue
} else {
this.option.infoTrue = true
}
//是否输出原图比例的截图
if (obj.full) {
this.option.full = obj.full
} else {
this.option.full = true
}
//图片根据截图框输出比例倍数
if (obj.enlarge) {
this.option.enlarge = obj.enlarge
} else {
this.option.enlarge = '1'
}
//图片默认渲染方式
if (obj.mode) {
this.option.mode = obj.mode
} else {
this.option.mode = 'contain'
}
if (obj.success) {
this.success = obj.success
} else {
this.success = () => {}
}
this.dialogVisiblex = true
},
finish() {
// 获取截图的数据
let that = this
this.$refs.cropper.getCropBlob(data => {
that.unimgurl = data
that.confirm()
})
},
confirm() {
this.success({
img: this.unimgurl
})
this.dialogVisiblex = false
},
cancel() {
this.dialogVisiblex = false
}
}
}
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.real_info_class {
.el-checkbox__input .el-checkbox__inner {
border-radius: 0;
}
}
.file-image {
width: 320px;
height: 320px;
font-size: 14px;
border: 1px solid #cccccc;
margin: 15px 0;
}
/* 截图 */
/* .cropper-content {} */
.cropper {
width: 960px;
height: 606px;
}
</style>
注意引入方式为
import VueCropper from "vue-cropper/src/vue-cropper.vue"
在upload标签下加上如下代码
下面贴出 完成的before-upload代码
beforeAvatarUpload(file) {
let _this = this
return new Promise((resolve, reject) => {
let types = ['image/jpeg', 'image/jpg', 'image/png'];
// let width = 140;
// let height = 140;
const isJPG = types.includes(file.type)
const isLt2M = file.size / 1024 / 1024 < 2
if (!isJPG) {
_this.$message.error('上传图片只能是 JPG 或 png格式!')
reject()
}
if (!isLt2M) {
_this.$message.error('上传图片大小不能超过 2MB!')
reject()
}
let _URL = window.URL || window.webkitURL;
//上传前对图片进行裁剪
_this.$refs.iscropper.showModal({
img: _URL.createObjectURL(file) , // 裁剪图片的地址
autoCropWidth: 140, // 默认生成截图框宽度
autoCropHeight: 140, // 默认生成截图框高度
fixedBox:true,
success: res => {
//拿到裁剪后图片没有name 属性
//file的name属性为只读 不能手动设置
//创建一个新的图片对象 设置原始文件名
const cloneFile = new File([res.img], file.name);
const formData = new FormData()
// console.log(param.file)
//通过 append 函数往formdata对象里传参,这里传的是后端需求的接口信息
formData.append('file', cloneFile)
//执行上传操作
request({
method: "post",
url: "/sys/file/upload/productImage",
data: formData,
headers: { "Content-Type": "multipart/form-data" },
}).then(response => {
//请求成功
_this.handleAvatarSuccess(response,cloneFile)
})
resolve()
}
})
})
}
讲一下大概的思路
- 第一步照常对上传文件做一个限制
- 打开裁剪框 设置固定的裁剪大小 并设置滚动放大缩小图片
- 由于裁剪后的图片没有文件名 并且文件名是只读 所以创建一个新的图片对象 并将图片原始文件名设置
- 文件传输是通过formdata上传的 创建formdata对象 将图片放在formdata对象中
- 上传成功后图片进行回显 并将图片id回传到业务数据中
handleAvatarSuccess(res,file) {
console.log(res)
if(res.code == 2000){
this.$successmsg(res.msg)
this.imageUrl = URL.createObjectURL(file);
this.ruleForm.productImg = res.data.id
}else{
this.$warnmsg(res.msg);
this.imageUrl = '';
this.ruleForm.productImg = ''
}
}
上传成功 后的操作 可根据自己 项目自定义
最后的效果
保存在本地的图片