Vue3 用户上传头像图片处理实时预览

标题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>

实现效果:
在这里插入图片描述
在这里插入图片描述
结果成功:
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值