首页 > 其他分享 >web技术分享| 图片上传与图片裁剪结合 vue3

web技术分享| 图片上传与图片裁剪结合 vue3

时间:2022-12-07 15:11:07浏览次数:49  
标签:web false img 裁剪 vue3 图片 上传 imgUpload

需求:

  • 上传的图片限制长宽相同;

  • 只能上传图片;

  • 图片大小限制 500k

  • 当前项目仅需要上传的图片信息

项目组件使用

裁剪:vue-cropper

import "vue-cropper/dist/index.css";
import { VueCropper } from "vue-cropper";

上传: Upload 上传(element plus 组件)

实现理论:

  1. 通过组件 Upload 进行图片上传前校验方法判断是否需要裁剪、是否是图片、是否超过大小限制;
  2. 裁剪后的图片限制大小;
  3. 上传的图片信息暴漏出组件;

组件调用

img-url 默认预览的图片
@img-upload 上传所需的最终图片

代码实现

页面

裁剪时弹窗显示

<!-- 上传 -->
  <el-upload
    class="uploader_cutsom"
    action=""
    :show-file-list="false"
    :accept="imgUpload.imgBmp"
    :http-request="updataImg"
    :before-upload="beforUpload"
  >
    <div v-if="imgUpload.imageUrl" class="w-full h-full relative">
      <img class="w-full h-full" :src="imgUpload.imageUrl" />
      <!-- 删除 -->
      <div
        @click="clearImg"
        class="absolute top-0 right-0 w-8 h-8 rounded flex items-center justify-center bg-black bg-opacity-30 text-white text-base z-20 cursor-pointer"
      >
        <i class="iconfont icon-shanchu"></i>
      </div>
    </div>

    <div v-else class="uploader_cutsom_default">
      <p>从你的计算机中</p>
      <p class="uploader_cutsom_default_button">选择文件</p>
    </div>
  </el-upload>
  <!-- 裁剪 -->
  <el-dialog
    v-model="imgUpload.dialogCropping"
    custom-class="dialog_custom"
    title="裁剪图片"
    append-to-body
    :close-on-press-escape="false"
    :show-close="false"
    :close-on-click-modal="false"
  >
    <div>
      <div class="h-96 w-full">
        <vueCropper
          ref="cropper"
          class="vue_cropper_custom"
          :img="imgCropping.imageUrl"
          :outputType="imgCropping.outputType"
          :autoCrop="imgCropping.autoCrop"
          :autoCropWidth="imgCropping.autoCropWidth"
          :autoCropHeight="imgCropping.autoCropHeight"
          :fixed="imgCropping.fixed"
          :fixedNumber="imgCropping.fixedNumber"
          :centerBox="imgCropping.centerBox"
          :full="imgCropping.full"
        ></vueCropper>
      </div>
    </div>
    <template #footer>
      <el-button v-focus @click="handleCropping($refs.cropper, false)">
        取消
      </el-button>
      <el-button
        v-focus
        type="primary"
        @click="handleCropping($refs.cropper, true)"
      >
        确定
      </el-button>
    </template>
  </el-dialog>

逻辑

/** 图片地址传递 */
const prop = defineProps({
  imgUrl: {
    type: String,
    default: "",
  },
});
/** 事件通知 */
const emit = defineEmits(["img-upload"]);

/** 图片上传 */
const imgUpload = reactive({
  // 是否展示裁剪
  dialogCropping: false,
  isCropping: false, // 判断是否已经截图
  // 图片
  imageUrl: "",
  // 图片格式
  imgBmp: "image/*",
  // 图片名称
  imgName: "",
});
// 图片上传前校验
const beforUpload: UploadProps["beforeUpload"] = async (rawFile) => {
  // 判断是否需要进行裁剪
  imgUpload.isCropping = (await imgSize(rawFile)) as boolean;
  // 图片名称
  imgUpload.imgName = rawFile.name;
  if (imgUpload.isCropping) {
    if (rawFile.type.indexOf("image/") === -1) {
      ElMessage.error("请上传正确的图片格式");
      return false;
    } else if (rawFile.size / 1024 / 1024 > 0.5) {
      ElMessage.error("图片大小不能超过 500k");
      return false;
    }
  } else {
    // 进入裁剪
    imgCropping.imageUrl = URL.createObjectURL(rawFile);
    imgUpload.dialogCropping = true;
    return false;
  }
};
// 上传
const updataImg = async (data: any) => {
  // 如果未截图,打开裁剪
  if (imgUpload.isCropping) {
    // 图片预览
    imgUpload.imageUrl = URL.createObjectURL(data.file);
    imgUpload.dialogCropping = false;
    imgUpload.isCropping = false;
    // 图片信息
    emit("img-upload", data.file);
  }
};

/** 图片裁剪 */
const imgCropping = reactive({
  imageUrl: "",
  // 裁剪生成图片的格式
  outputType: "png",
  // 是否默认生成截图框
  autoCrop: true,
  // 上传图片按照原始比例渲染
  //   original: true,
  // 是否输出原图比例的截图
  full: false,
  // 默认生成截图框宽度
  autoCropWidth: 160,
  // 默认生成截图框高度
  autoCropHeight: 160,
  // 是否开启截图框宽高固定比例
  fixed: true,
  // 截图框的宽高比例
  fixedNumber: [1, 1],
  // 截图框是否被限制在图片里面
  centerBox: true,
});

// 生成裁剪图片
const handleCropping = (roleRefs: any, type: boolean) => {
  if (type) {
    roleRefs.getCropBlob((data: any) => {
      // 判断裁剪图片大小
      if (data.size / 1024 / 1024 > 0.5) {
        ElMessage.error("裁剪图片大小不能超过 500k");
      } else {
        // 图片预览
        imgUpload.imageUrl = URL.createObjectURL(data);
        imgUpload.dialogCropping = false; 
        // 图片信息
        emit("img-upload", blobToFile(data, imgUpload.imgName));
      }
    });
  } else {
    imgUpload.imageUrl = "";
    imgUpload.dialogCropping = false;
  }
};

// 清除图片
const clearImg = () => {
  imgUpload.imageUrl = "";
  emit("img-upload");
};

onMounted(() => {
  // 图片地址传递
  imgUpload.imageUrl = prop.imgUrl;
});

图片相关方法封装

/** 查询图片大小 */
export const imgSize = (file: any) => {
  return new Promise((resolve, reject) => {
    let reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => {
      // 让页面中的img标签的src指向读取的路径
      let img = new Image();
      img.src = reader.result as string;
      if (img.complete) {
        // 如果存在浏览器缓存中
        if (img.width / img.height !== 1) {
          resolve(false);
        } else {
          resolve(true);
        }
      } else {
        img.onload = () => {
          if (img.width / img.height !== 1) {
            resolve(false);
          } else {
            resolve(true);
          }
        };
      }
    };
  });
};

/**
 * 文件格式转换
 * @description blobToFile
 * @param {Blob} blob
 * @param {String} fileName
 */
export const blobToFile = (blob: any, fileName: string) => {
  return new window.File([blob], fileName, {
    type: blob.type,
  });
};

在这里插入图片描述

标签:web,false,img,裁剪,vue3,图片,上传,imgUpload
From: https://www.cnblogs.com/anyrtc/p/16963121.html

相关文章

  • 图片 base64 编码
     通常我们在使用服务的时候,数据从我们的设备传输到服务器,往往会有两种方式:一是直接传输文件,但这种情况受网络情况影响较大,文件可能传不过去,并且文件直接在网路上传播,你的......
  • html2canvas 下载图片
    html2canvas(that.$app,{'width':that.$app.get(0).offsetWidth,'height':that.$app.get(0).scrollHeight,'ba......
  • WebGL之Matrix4库
    1.Matrix4是由<<WebGL编程指南>>作者写的提供WebGL的4*4矩阵操作的方法库,简化我们编写的代码。源代码共享地址,点击链接:Matrix4源代码。参考:https://www.cnblogs.com/w-wa......
  • Webpack完整打包流程分析
    前言webpack在前端工程领域起到了中流砥柱的作用,理解它的内部实现机制会对你的工程建设提供很大的帮助(不论是定制功能还是优化打包)。下面我们基于webpack5源码结构,对......
  • Webpack插件核心原理
    引言围绕Webpack打包流程中最核心的机制就是所谓的Plugin机制。所谓插件即是webpack生态中最关键的部分,它为社区用户提供了一种强有力的方式来直接触及webpack......
  • Webpack中的高级特性
    自从webpack4以后,官方帮我们集成了很多特性,比如在生产模式下代码压缩自动开启等,这篇文章我们一起来探讨一下webpack给我们提供的高级特性助力开发。探索webpack的高级特性......
  • anvas保存图片时,谷歌浏览器Chrome报错【解决方案】Not allowed to navigate top frame
    varbase64Data=canvas.toDataURL("image/png");variframe="<iframewidt......
  • JavaWeb商城项目的商品点赞功能模块的开发详
    一.JavaWeb商城项目的商品点赞功能开发过程记录1.1项目背景在完成内蒙古科技大学JavaWeb课程的大作业之后,本着练习的态度继续的写了一个功能:点赞功能。本需求看似简单,难......
  • vscode中引用vue3时红色提示
    从GitHub上下载了一个前端项目学习,用vscode打开。“vue3+vite”在vscode控制台执行npminstall,安装所需要的各种包。这个时候可以用npmrundev,启动项目。但是vs......
  • Vue3必会技巧-自定义Hooks
    Vue3自定义Hooks定义:个人理解:一些可复用的方法像钩子一样挂着,可以随时被引入和调用以实现高内聚低耦合的目标,应该都能算是hook;为什么Vue3要用自定义Hook?:结论:就是为了......