上传文件时候接到一个需求 商品必须为固定尺寸 在网上找的 基本在 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 = ''
}
}
上传成功 后的操作 可根据自己 项目自定义
最后的效果
保存在本地的图片