1
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 组件)
实现理论:
通过组件 Upload 进行图片上传前校验方法判断是否需要裁剪、是否是图片、是否超过大小限制;
裁剪后的图片限制大小;
上传的图片信息暴漏出组件;
组件调用
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
版权声明: 本文为 InfoQ 作者【anyRTC开发者】的原创文章。
原文链接:【http://xie.infoq.cn/article/c79022e9351a40f5bfc97d0e9】。文章转载请联系作者。
anyRTC开发者
关注
实时交互,万物互联! 2020-08-10 加入
实时交互,万物互联,全球实时互动云服务商领跑者!









    
评论