写点什么

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

作者:anyRTC开发者
  • 2022-12-07
    上海
  • 本文字数:2943 字

    阅读完需:约 10 分钟

需求:

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

  • 只能上传图片;

  • 图片大小限制 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, });};
复制代码



发布于: 刚刚阅读数: 8
用户头像

实时交互,万物互联! 2020-08-10 加入

实时交互,万物互联,全球实时互动云服务商领跑者!

评论

发布
暂无评论
web技术分享| 图片上传与图片裁剪结合 vue3_Vue_anyRTC开发者_InfoQ写作社区