标题Vue3 用户上传头像图片处理实时预览
<template>
<div>
<!-- 使用 label 标签与 input 绑定,实现点击图片打开文件选择器 -->
<label for="avatarInput">
<lay-avatar :src="avatarUrl" alt="Avatar" class="avatar" @click="openImagePicker">
+上传头像
</lay-avatar>
</label>
<!-- 隐藏的 input 元素,用于实际的文件选择 -->
<input id="avatarInput" type="file" style="display: none" @change="handleFileChange" accept="image/png, image/jpeg">
</div>
</template>
<script>
export default {
// 组件名称
// eslint-disable-next-line vue/multi-word-component-names
name: "Avatar",
data() {
return {
avatarUrl: '', // 用户头像 URL
avatarFile: null, // 用户选择的图片文件
};
},
methods: {
/**
* 处理文件选择后的变化
* @param {Event} event - 触发改变的事件对象
*/
handleFileChange(event) {
const {files} = event.target;
const file = files[0];
if (!file) return;
if (!['image/png', 'image/jpeg'].includes(file.type)) {
alert('请选择 .png 或 .jpg 格式的图片');
return;
}
this.avatarFile = file;
this.previewAvatar();
},
/**
* 触发打开文件选择器
*/
openImagePicker() {
// 获取并触发关联的 input 元素的点击事件
const inputElement = this.$el.querySelector('input[type="file"]');
inputElement.click();
},
/**
* 预览选定的头像
*/
previewAvatar() {
const reader = new FileReader();
reader.onload = (event) => {
this.avatarUrl = event.target.result;
this.compressAndUpload();
};
reader.readAsDataURL(this.avatarFile);
},
/**
* 压缩并上传头像
*/
compressAndUpload() {
const quality = 0.7; // 图片压缩质量
const maxWidth = 400; // 图片最大宽度
const maxHeight = 600; // 图片最大高度
const maxSizeKB = 30; // 图片最大大小(KB)
const img = new Image();
img.src = this.avatarUrl;
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
let width = img.width;
let height = img.height;
// 根据比例缩放图片
if (width > height) {
if (width > maxWidth) {
height *= maxWidth / width;
width = maxWidth;
}
} else {
if (height > maxHeight) {
width *= maxHeight / height;
height = maxHeight;
}
}
canvas.width = width;
canvas.height = height;
// 将图片绘制到 canvas 上
ctx.drawImage(img, 0, 0, width, height);
// 压缩图片并转换为 base64 格式
canvas.toBlob((blob) => {
const compressedFile = new File([blob], this.avatarFile.name, { type: 'image/jpeg', lastModified: Date.now() });
if (compressedFile.size / 1024 > maxSizeKB) {
alert('图片大小超过限制,请重新选择');
return;
}
this.avatarFile = compressedFile;
}, 'image/jpeg', quality);
};
},
},
};
</script>
<style>
.avatar {
border-radius: 50%;
width: 100px;
height: 100px;
background: rgba(111, 120, 131, 0.67);
}
</style>
实现效果:
结果成功: