1. 效果预览
2. 插件介绍
官网地址:[GitHub - xyxiao001/vue-cropper: A simple picture clipping plugin for vue](https://github.com/xyxiao001/vue-cropper?from=thosefree.com)
3 . 插件使用
下载插件
npm install vue-cropper@next
3 . 封装好的代码,拿来用即可
使用注意点
-
组件内引用-必须
-
import 'vue-cropper/dist/index.css' import {VueCropper} from 'vue-cropper' import {getCurrentInstance, ref, reactive, watch} from 'vue'
-
-
如下片段可自行更改,
-
const dp = defineProps({ // 接收父组件参数 realTime: "", // 实时时间 }) const de = defineEmits(["popUpClose"]) const avatarUpload = () => { // 图片上传事件 cropper.value.getCropBlob(data => { const formData = new FormData(); formData.append("id", sessionStorage.getItem("userid")); formData.append('mf',data); // file是你的文件对 axios.post('/person/uploadAvatar', formData) .then(response => { // 处理后台返回的结果 if(response.code !== 200) return ElMessage.error(response.msg) ElMessage.success(response.msg) de("popUpClose", response.data) }) .catch(error => { // 处理错误 ElMessage.error(error.message) throw error }); }) }
-
封装组件代码:
<template>
<div class = "avatar-container" @click = "">
<el-row>
<el-col :span = "12" style = "width: 600px; height: 300px">
<vue-cropper
ref = "cropper"
:img = "options.img"
:info = "true"
:autoCrop = "options.autoCrop"
:autoCropWidth = "options.autoCropWidth"
:autoCropHeight = "options.autoCropHeight"
:fixedBox = "options.fixedBox"
:outputType = "options.outputType"
@realTime = "realTime"
/>
</el-col>
<!-- 实时预览部分 -->
<el-col :span = "12" style = "height: 300px">
<div class = "preview-box">
<img v-if = "previews.url" :src = "previews.url" :style="previews.img"/>
<span v-else></span>
</div>
</el-col>
</el-row>
<el-row style = "margin-top: 12px">
<el-col :span = "12">
<el-row>
<el-col :span = "8">
<el-upload
action = "#"
:http-request = "() => {}"
:before-upload = "beforeUpload"
:show-file-list = "false"
>
<el-button>选择</el-button>
</el-upload>
</el-col>
<el-col :span = "4">
<el-button :icon = "Plus" @click = "changeScale(1)"></el-button>
</el-col>
<el-col :span = "4">
<el-button :icon = "Minus" @click = "changeScale(-1)"></el-button>
</el-col>
<el-col :span = "4">
<el-button :icon = "RefreshLeft" @click = "rotateLeft()"></el-button>
</el-col>
<el-col :span = "4">
<el-button :icon = "RefreshRight" @click = "rotateRight()"></el-button>
</el-col>
</el-row>
</el-col>
<el-col :span = "4" :offset = "8" style = "margin-left: 22.3%">
<el-button type = "primary" @click = "avatarUpload()">提 交</el-button>
</el-col>
</el-row>
</div>
</template>
<script setup>
import {Plus, Minus, RefreshLeft, RefreshRight} from '@element-plus/icons-vue'
import {ElMessage} from 'element-plus'
import 'vue-cropper/dist/index.css'
import {VueCropper} from 'vue-cropper'
import {getCurrentInstance, ref, reactive, watch} from 'vue'
import axios from "axios";
const {proxy} = getCurrentInstance()
const options = reactive({
img: "https://tse1-mm.cn.bing.net/th/id/OIP-C.rBx_awzG233bGXk-4h3eeAHaFL?w=262&h=184&c=7&r=0&o=5&dpr=1.3&pid=1.7", // 裁剪图片的地址
autoCropWidth: 200, // 默认生成截图框宽度 默认容器的 80%
autoCropHeight: 200, // 默认生成截图框高度 默认容器的 80%
outputType: 'png', // 裁剪生成图片的格式 jpeg, png, webp
autoCrop: true, // 是否默认生成截图框
fixedBox: false // 固定截图框大小
})
let previews = ref({
url: '',
img: '',
})
// 修改图片大小 正数为变大 负数变小
const changeScale = (num) => {
num = num || 1
proxy.$refs.cropper.changeScale(num)
}
// 向左边旋转90度
const rotateLeft = () => {
proxy.$refs.cropper.rotateLeft()
}
// 向右边旋转90度
const rotateRight = () => {
proxy.$refs.cropper.rotateRight()
}
// 上传图片处理
const beforeUpload = (rawFile) => {
if (rawFile.type.indexOf('image/') == -1) {
ElMessage.error('请上传图片类型文件!')
return false
}
if (rawFile.size / 1024 / 1024 > 2) {
ElMessage.error('文件大小不能超过2MB!')
return false
}
const reader = new FileReader()
reader.readAsDataURL(rawFile)
reader.onload = () => {
// 图片在这里
if (typeof reader.result === "string") {
options.img = reader.result
}
}
}
// 实时预览事件
const realTime = (data) => {
previews.value = data
}
const cropper = ref(null);
const getBase64 = () => { // 获取截图的base64编码
cropper.value.getCropData(data => {
console.log(data)
})
}
const getBlob = () => { // 获取截图的blob
cropper.value.getCropBlob(data => {
console.log(data)
})
}
const dp = defineProps({ // 接收父组件参数
realTime: "", // 实时时间
})
const de = defineEmits(["popUpClose"])
const avatarUpload = () => { // 图片上传事件
console.log(sessionStorage.getItem("userid"))
cropper.value.getCropBlob(data => {
const formData = new FormData();
formData.append("id", sessionStorage.getItem("userid"));
formData.append('mf',data); // file是你的文件对
axios.post('/person/uploadAvatar', formData)
.then(response => { // 处理后台返回的结果
if(response.code !== 200) return ElMessage.error(response.msg)
ElMessage.success(response.msg)
de("popUpClose", response.data)
})
.catch(error => { // 处理错误
ElMessage.error(error.message)
throw error
});
})
}
</script>
<style lang = "scss" scoped>
.avatar-container {
.img-box {
border-radius: 50%;
border: 1px solid #ccc;
width: 10vw;
height: 10vw;
}
}
.preview-box {
position: absolute;
top: 50%;
transform: translate(50%, -50%);
width: 200px;
height: 200px;
border-radius: 50%;
border: 1px solid #ccc;
overflow: hidden;
}
</style>
父组件代码 - 【可要可不要】
效果预览
注意点
- 根据自己的需求舍 - 留
<script setup>
import {useRoute, useRouter} from 'vue-router';
import {onMounted, reactive, ref} from "vue";
import AvatarUpload from "./avatarUpload.vue";
const router = useRouter()
const rt = reactive({
personDTO: {}, // 个人信息对象
show: false,
realTime: '', // 实时时间
})
const popUpClose = (data) => {
rt.show = false // 关闭
rt.personDTO.photo = data // 更新头像
}
let showOverlay = ref(false)
const upload = () => { // 用户头像上传
if(showOverlay) {
console.log("uploading avatar")
rt.show = true
rt.realTime = new Date().getTime()
}
}
</script>
<template>
<el-row :gutter = "20">
<el-col :span = "6"> <!-- 左卡片 -->
<el-card>
<div>个人信息</div>
<el-divider/>
<el-row type = "flex" justify = "center">
<div
@mouseover = "showOverlay = true"
@mouseleave = "showOverlay = false"
@click = "upload()"
style = "position: relative; cursor: pointer;">
<el-avatar :size = "120" :src = "`data:image/png;base64,${rt.personDTO.photo}`"/>
<div v-if = "showOverlay"
style = "position: absolute; border-radius:50%; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center;">
<span style = "color: white; font-size: 24px;">+</span>
</div>
</div>
</el-row>
<!--弹出编辑-->
<el-dialog v-model = "rt.show" style = "width:1000px; height: 800px">
<AvatarUpload @popUpClose = "popUpClose" :realTime = "rt.realTime"/>
</el-dialog>
<el-divider/>
</el-card>
</el-col>
</el-row>
</template>
<style scoped>
* {
font-size: 12px;
}
.el-text-right {
text-align: right;
}
</style>
EDN ! !!