需求:因为上传图片过大,导致页面闪退,要求图片可裁剪(类似弹窗),然后再进行上传并且显示
事例图
注意:vue2和vue3所需要的vue-cropperjs版本不一致,安装时注意版本;
1、下载
npm install vue-cropperjs@4 cropperjs
2、安装
在plugins下创建vue-cropperjs.js文件
import Vue from 'vue'
import VueCropper from 'vue-cropperjs'
import 'cropperjs/dist/cropper.css'
Vue.component('vue-cropper', VueCropper)
并且nuxt2是服务端渲染,所以需要在nuxt.config.js中添加一些配置:
export default {
...
plugins:[
...
{ src:'@/plugins/vue-cropperjs', ssr: false }
]
}
3、因为该需求只需在一个页面实现,所以博主就没有封装组件,直接在页面中使用
import VueCropper from 'vue-cropperjs'
import 'cropperjs/dist/cropper.css'
export default {
components:{
VueCropper
}
}
相关html代码
<div class="avatar-bg">
<img v-if="userInfo.avatar" :src="getImageUrl(userInfo.avatar)">
<input type="file" title="" accept="image/jpeg, image/png" class="img-input" @change="addHeadImg">
<div class="img-font">
上传
</div>
</div>
<!-- 剪裁图片 -->
<div v-if="cropperImage">
<div class="cropper-shadow"></div>
<div class="cropper-img">
<img class="cropper-close" src="../../assets/img/close.png" @click="closeCropper">
<div style="display: flex">
<div style="width: 400px;height: 400px;margin-left: 40px;margin-top: 40px;">
<VueCropper
ref="cropper"
:src="imgData"
:view-mode="2"
:aspect-ratio="1"
:autoCropArea="0.5"
:movable="false"
:zoomable="false"
:drag-mode="'move'"
:img-style="{ 'width': '400px','height': '400px' }"
@crop="onCrop"
/>
</div>
<div class="cropper-right">
<img class="cropper-region" :src="croppedImageUrl" />
<div style="width: 100%;text-align: center;margin-top: 10px">
200px*200px
</div>
</div>
</div>
<div class="btn-box">
<button class="btn-left" @click="closeCropper">
取消
</button>
<button class="btn-right" @click="uploadImage">
上传
</button>
</div>
</div>
</div>
注意: autoCropArea取值(0~1),可调节裁剪框的大小。并且vueCropper外层需包裹一层div,并且必须设置宽高
相关js代码
export default {
data(){
...
cropperImage: false,
imgData: null,
cropperCanvas: null
},
computed:{
croppedImageUrl () {
if (this.cropperImage && this.cropperCanvas) {
return this.cropperCanvas.toDataURL('image/jpeg')
}
return null
}
},
methods:{
/* 裁剪头像 */
addHeadImg (event) {
const file = event.target.files[0]
if (file) {
const reader = new FileReader()
// 转化为base64
reader.readAsDataURL(file)
reader.onload = (e) => {
this.cropperImage = true
this.imgData = e.target.result
}
}
},
/* 裁剪框变化时的回调函数 */
onCrop () {
this.cropperCanvas = this.$refs.cropper.getCroppedCanvas()
},
/* 上传头像 */
uploadImage () {
const croppedCanvas = this.$refs.cropper.getCroppedCanvas()
croppedCanvas.toBlob(async (blob) => {
const formData = new FormData()
formData.append('uploadFile', blob)
const result = await this.$api.uploadApi(formData)
if (result.status === 0) {
this.$message({ message: '修改成功', type: 'success' })
this.userInfo.avatar = result.data.filePath
} else {
this.$message({ showClose: true, message: '修改失败', type: 'error', duration: 3000 })
}
this.closeCropper()
})
}
}
}
相关css代码
.avatar-bg {
width: 56px;
height: 56px;
border-radius: 50%;
background: #F6F6F6;
border: 1px solid #F0F0F0;
position: relative;
img {
height: 54px;
width: 54px;
border-radius: 50%;
}
&:hover {
.img-font {
display: block;
}
}
}
.img-input {
z-index: 3;
opacity: 0;
cursor: pointer;
left: 0;
top: 0;
position: absolute;
height: 54px;
width: 54px;
border-radius: 50%;
}
.img-font {
display: none;
background: rgba(0,0,0,.8);
height: 54px;
width: 54px;
line-height: 54px;
font-size: 14px;
text-align: center;
color: #fff;
position: absolute;
z-index: 1;
top: 0;
cursor: pointer;
border-radius: 50%;
}
.cropper-shadow {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9999;
}
.cropper-img {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 720px;
height: 530px;
background-color: #FFFFFF;
border-radius: 5px;
z-index: 10000;
.cropper-close {
float: right;
margin-right: 15px;
margin-top: 15px;
width: 20px;
height: 20px;
}
.cropper-left {
margin-left: 40px;
margin-top: 40px;
width: 400px;
height: 400px;
}
.cropper-right {
margin-top: 40px;
margin-left: 40px;
.cropper-region {
width: 200px;
height: 200px;
border-radius: 50%;
border: 1px solid #ebebeb;
}
}
.btn-box {
display: flex;
margin-top: 40px;
justify-content: center;
.btn-left {
width: 64px;
height: 33px;
border: 1px solid #ebebeb;
border-radius: 2px;
background-color: #FFFFFF;
text-align: center;
line-height: 33px;
}
.btn-right {
margin-left: 25px;
width: 64px;
height: 33px;
border: 1px solid #2875E8;
border-radius: 2px;
background-color: #2875E8;
text-align: center;
line-height: 33px;
color: #FFFFFF;
}
}
}