要实现头像上传并裁剪的功能,可以使用以下步骤:
-
安装依赖:首先,你需要安装一些依赖。你可以选择使用 Element Plus 或 Ant Design Vue 组件库,具体选择哪个取决于你的需求。你还需要安装其他一些依赖,如 axios(用于发送请求到服务器)和 vue-cropper(用于裁剪头像)。
使用 Element Plus 组件库的话,可以通过以下命令进行安装:
npm install element-plus axios vue-cropper
使用 Ant Design Vue 组件库的话,可以通过以下命令进行安装:
npm install ant-design-vue axios vue-cropper
-
创建上传组件:创建一个头像上传组件,其中包含一个上传按钮和一个预览区域。根据你选择的组件库,可以使用
el-upload
(Element Plus)或a-upload
(Ant Design Vue)组件来实现上传功能。使用img
标签来预览头像。对于 Element Plus 组件库,上传组件可以如下所示:
<template> <el-upload action="your-upload-api-url" :before-upload="beforeUpload" :on-success="onSuccess"> <img v-if="imageUrl" :src="imageUrl" alt="Avatar" style="width: 120px; height: 120px; border-radius: 50%"> <i v-else class="el-icon-plus avatar-uploader-icon"></i> </el-upload> </template> <script> export default { data() { return { imageUrl: '', }; }, methods: { beforeUpload(file) { const isJPG = file.type === 'image/jpeg'; const isPNG = file.type === 'image/png'; const isLt2M = file.size / 1024 / 1024 < 2; if (!isJPG && !isPNG) { this.$message.error('只支持上传 JPG 和 PNG 格式的图片'); } if (!isLt2M) { this.$message.error('图片大小不能超过 2MB'); } return (isJPG || isPNG) && isLt2M; }, onSuccess(response) { this.imageUrl = response.url; }, }, }; </script>
对于 Ant Design Vue 组件库,上传组件可以如下所示:
<template> <a-upload action="your-upload-api-url" :before-upload="beforeUpload" :custom-request="customRequest" :transform-file="transformFile"> <img v-if="imageUrl" :src="imageUrl" alt="Avatar" style="width: 120px; height: 120px; border-radius: 50%"> <a-icon v-else type="plus" class="avatar-uploader-trigger"></a-icon> </a-upload> </template> <script> import { message } from 'ant-design-vue'; export default { data() { return { imageUrl: '', }; }, methods: { beforeUpload(file) { const isJPG = file.type === 'image/jpeg'; const isPNG = file.type === 'image/png'; const isLt2M = file.size / 1024 / 1024 < 2; if (!isJPG && !isPNG) { message.error('只支持上传 JPG 和 PNG 格式的图片'); } if (!isLt2M) { message.error('图片大小不能超过 2MB'); } return (isJPG || isPNG) && isLt2M; }, customRequest({ file }) { const formData = new FormData(); formData.append('file', file); axios.post('your-upload-api-url', formData) .then(response => { this.imageUrl = response.data.url; }) .catch(error => { console.log(error); message.error('上传失败'); }); }, transformFile(file) { return new Promise(resolve => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => { const img = document.createElement('img'); img.src = reader.result; img.onload = () => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0, img.width, img.height); canvas.toBlob(blob => { resolve(blob); }, 'image/jpeg', 0.8); }; }; }); }, }, }; </script>
以上代码中的
your-upload-api-url
需要替换为你的上传接口地址。 -
添加裁剪功能:为了实现头像裁剪功能,你可以使用
vue-cropper
组件。首先,安装该组件:npm install vue-cropper
接下来,修改上传组件,添加一个裁剪按钮和一个裁剪区域:
<template> <el-upload action="your-upload-api-url" :before-upload="beforeUpload" :on-success="onSuccess"> <div v-if="!imageUrl" class="avatar-uploader"> <i class="el-icon-plus avatar-uploader-icon"></i> </div> <div v-else class="avatar-container"> <img :src="imageUrl" alt="Avatar" class="avatar"> <a-button type="primary" @click="showCropper">裁剪</a-button> </div> </el-upload> <div v-show="showCropper" class="cropper-wrapper"> <vue-cropper ref="cropper" :src="imageUrl" :auto-crop="true" :auto-zoom="true" :output-type="'png'" :output-quality="1" :fixed-box="true" :fixed-number="[1, 1]" :can-move="true" :can-move-box="true" :drag-mode="'move'" :modal="true" :preview=".cropper-preview" :view-mode="2" :center-box="true" :center-radius="1" :guides="false" :background="'#ffffff'" :zoom-step=".1" :rect-color="'#ff0000'" @crop-upload="cropUpload" @close="closeCropper"> </vue-cropper> </div> </template> <script> import { ref } from 'vue'; import { message } from 'element-plus'; //或者import { message } from 'ant-design-vue'; export default { setup() { const showCropper = ref(false); return { showCropper, }; }, data() { return { imageUrl: '', }; }, methods: { beforeUpload(file) { const isJPG = file.type === 'image/jpeg'; const isPNG = file.type === 'image/png'; const isLt2M = file.size / 1024 / 1024 < 2; if (!isJPG && !isPNG) { this.$message.error('只支持上传 JPG 和 PNG 格式的图片'); } if (!isLt2M) { this.$message.error('图片大小不能超过 2MB'); } return (isJPG || isPNG) && isLt2M; }, onSuccess(response) { this.imageUrl = response.url; }, showCropper() { this.showCropper = true; }, closeCropper() { this.showCropper = false; }, cropUpload(dataUrl) { const blob = this.dataURLtoBlob(dataUrl); const formData = new FormData(); formData.append('file', blob); axios.post('your-upload-api-url', formData) .then(response => { this.imageUrl = response.data.url; this.closeCropper(); }) .catch(error => { console.log(error); message.error('上传失败'); }); }, dataURLtoBlob(dataURL) { const arr = dataURL.split(','); const mime = arr[0].match(/:(.*?);/)[1]; const bstr = atob(arr[1]); let n = bstr.length; const u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); }, }, }; </script> <style> .avatar-uploader { border: 1px dashed #d9d9d9; border-radius: 6px; cursor: pointer; overflow: hidden; position: relative;