vue3中使用el-upload + tui-image-editor进行图片处理

效果如下

看之前请先看上一篇《vue3中使用组件tui-image-editor进行图片处理 》中的
1、第一步安装
2、第二部封装组件

本篇只是在这基础上结合el-upload使用组件
3、第三步结合el-upload使用组件

javascript 复制代码
<template>
  <el-dialog
    :title="dialogTitle"
    :modelValue="dialogVisible"
    width="55%"
    top="4vh"
    :before-close="closeDialog"
    :close-on-click-modal="false"
    destroy-on-close
  >
    <div class="newBox">
      
      <el-upload
        class="img-edit"
        :show-file-list="false"
        :accept="cropperObj.accpetType"
        :limit="cropperObj.limit"
        :on-change="cropperObj.handleAvatarSuccess"
        :before-upload="cropperObj.beforeAvatarUpload"
        :disabled="cropperObj.dealPicShow"
      >
        <div class="imgCorpper" v-if="cropperObj.dealPicShow"  @mouseenter="cropperObj.buttonopen" @mouseleave="cropperObj.buttonexit">
          <div class="imgCorpperY">
            <el-image  
            :src="cropperObj.previewViewer"
            :zoom-rate="1.2"
            :preview-src-list="cropperObj.srcList"
            :initial-index="4"
            fit="cover"/> 
            <el-image-viewer
              v-if="cropperObj.showImageViewer"
              @close="cropperObj.closeImgView"
              :url-list="cropperObj.srcList"
            />
            <div :class="cropperObj.showBack?'imgcurrent show':'imgcurrent'"  >
              <div class="imgBack"></div>
              <div class="imgicon">
                <el-icon @click="cropperObj.showPic"><ZoomIn /></el-icon>
                <el-icon @click="cropperObj.delePic"><Delete /></el-icon>
              </div>
            </div>
          </div>
        </div>
        <el-icon v-else class="img-edit-icon"><Plus /></el-icon>
      </el-upload>
      <!-- 上传提示 -->
      <div class="el-upload__tip" v-if="!cropperObj.dealPicShow">
        请上传大小不超过 <b style="color: #f56c6c">{{ cropperObj.fileSize }}MB</b>格式为 <b style="color: #f56c6c">{{ cropperObj.fileType.join("/") }}</b>的文件
      </div>
      <!-- 图片处理框 -->
      <SignImage 
        v-if="cropperObj.cVisible" 
        :dialogVisible.sync="cropperObj.cVisible" 
        :title="cropperObj.ctitle"
        :imgUrl="cropperObj.previewsImgUrl"
        @getNewImg="cropperObj.getNewImg"
        @closeCropperDialog="cropperObj.closeCropperView"
      ></SignImage>

    </div>
    
    <template #footer>
      <div class="dialog-footer">
        <!-- <el-button class="btn-sure" type="primary" @click="closeDialog">确 定</el-button> -->
        <el-button @click="closeDialog">取 消</el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup>
import SignImage from '@/components/SignImage/index.vue'
import { importNewImg, editNewImg } from "@/api/back/home.js";
import { ref, reactive, watch } from "vue";

  const props = defineProps({
    dialogVisible: {
      type: Boolean,
      default: false,
    },
    dialogTitle: {
      type: String,
      default: "",
    },
    
  });

  // 关闭弹窗
  const emits = defineEmits(["closeDialog"]);
  const closeDialog = () => {
    emits("closeDialog");
  };


// new 背景图片
const cropperObj = reactive({
  fileType: ["png", "jpg", "jpeg"],
  accpetType:".png,.jpg,.jpeg",
  limit:1,
  fileSize:10,
  cVisible:false, // 显示切图弹框
  ctitle:"", // 弹框标题
  imgShow:false, //是否有图片
  previewsImgUrl:"", //图片地址
  srcList:[], //图片预览地址数组
  showBack:false, // 预览删除图层是否展示
  showImageViewer:false, // 是否预览
  previewViewer:"", // 处理后的图片地址
  dealPicShow:false, // 是否删除了处理后的图片
  // 开启编辑弹框
  openCropperView: () => {
    cropperObj.ctitle="图片"
    cropperObj.cVisible = true 
  },
  // 关闭编辑弹框所触发的事件
  closeCropperView: (data)=> {
    cropperObj.cVisible = false
  },
  // 预览删除图层显示
  buttonopen: ()=>{
    cropperObj.showBack = true
  },
  // 预览删除图层隐藏
  buttonexit: ()=>{
    cropperObj.showBack = false
  },
  // 预览开启
  showPic: ()=>{
    cropperObj.showImageViewer = true
  },
  // 预览隐藏
  closeImgView: ()=>{
    cropperObj.showImageViewer = false
  },
  // 删除图片
  delePic:()=>{
    cropperObj.previewsImgUrl ="";
    cropperObj.previewViewer = ""
    cropperObj.srcList=[]
    setTimeout(function(){
      cropperObj.dealPicShow = false
    },1000)
    cropperObj.imgShow = false
    // formData.backgroundUrl = "";
  },
  // 获取处理完的图片
  getNewImg:(val) =>{
    cropperObj.previewViewer = window.serverUrl.IMG_SERVER + val
    cropperObj.dealPicShow = true
    cropperObj.srcList=[cropperObj.previewViewer]
    // formData.backgroundUrl = val;
  },
  beforeAvatarUpload:(file)=> {
    let isImg = false;
    let fileExtension = "";
    if (cropperObj.fileType.length) {
      if (file.name.lastIndexOf(".") > -1) {
        fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
      }
      isImg = cropperObj.fileType.some((type) => {
        if (file.raw.type.indexOf(type) > -1) return true;
        if (fileExtension && fileExtension.indexOf(type) > -1) return true;
        return false;
      });
    } else {
      isImg = file.type.indexOf("image") > -1;
    }
    if (!isImg) {
      ElMessage.error(`格式不正确, 请上传${cropperObj.fileType.join("/")}图片格式文件!`);
      return false;
    } else {
      isImg = true;
    }
    if (cropperObj.fileSize) {
      const isLt = file.size / 1024 / 1024 < cropperObj.fileSize;
      if (!isLt) {
        proxy.$modal.msgError(`上传大小不能超过 ${cropperObj.fileSize} MB!`);
        // fileList.value = [];
        return false;
      }
    }
  },
  handleAvatarSuccess:(file, fileList)=> {
    const bgFormData = new FormData()
    bgFormData.append("file", file.raw);
    importNewImg(bgFormData).then(res => {
      cropperObj.previewsImgUrl = window.serverUrl.IMG_SERVER + res.fileName
      cropperObj.ctitle="图片处理"
      cropperObj.cVisible = true 
    })
  },
})


</script>

<style lang="scss"  scoped>
  .img-edit{
    display: flex;
    justify-content: center;
    align-items: center;
    font-size:1rem;
    width:148px;
    height: 148px;
    border:1px dashed #cdd0d6;
    position: relative;
    border-radius: 6px;
    .el-icon{
      width:0.35rem;
      height: 0.35rem;
      color:#909399;
    }
    .imgCorpper{
    display: flex;
    justify-content: center;
    align-items: center;
    font-size:1rem;
    width:148px;
    height: 148px;
    border:1px dashed #cdd0d6;
    position: relative;
    border-radius: 6px;
    cursor:pointer;
    .el-icon{
      width:0.35rem;
      height: 0.35rem;
      color:#909399;
    }
    .imgCorpperY{
      position: relative;
      width: 100%;
      height: 100%;
      border-radius: 6px;
      overflow: hidden;
      height: 100%;;
      >img{
        width: 100%;
        height: 100%;;
      }
      .el-image{
        width: 100%;
        height: 148px;
        max-height: 100%;;
      }
      .imgcurrent{
          display: none;
          position: absolute;
          width: 100%;
          height: 100%;
          top: 0;
          .imgBack{
            background: #00000082;
            width: 100%;
            height: 100%;
            position: absolute;
            z-index: 1;
          }
          .imgicon{
            position: absolute;
            width: 60%;
            margin: 0 20%;
            height: 100%;
            display: flex;
            justify-content: space-between;
            align-items: center;
            color: #fff;
            z-index: 2;
            .el-icon{
              color: #fff;
              // font-size: 1rem;
            }
          }
        }
        >.show{
          display:block;
        }
      }
    }
  }
  .img-edit:hover {
    border-color: #409EFF;
  }
</style>
相关推荐
无限聚核几秒前
抖音 certificate.prepare 之后怎么验券?和美团 msconsume 差在哪,无限聚核
前端·微信小程序
2603_9658966210 分钟前
Grid 网格布局|CSS 二维页面排版体系
前端·css
有味道的男人25 分钟前
搜好货平台关键词商品搜索接口:分页容错与商品数据轻量化提取方案
服务器·前端·javascript
lovingsoft1 小时前
Chrome Lighthouse 详解
前端·chrome
Qlly1 小时前
全栈工程师怎么接需求?从一句「加个功能」聊到能开发、能验收
前端·后端
马可家的菠萝1 小时前
你的微信“文件传输助手”,是不是已经成了第二个网盘?
前端·后端·架构
略略略啦1 小时前
Vibe Coding 基于Spec DD和TDD的实践指南
前端
shmily麻瓜小菜鸡2 小时前
前端实现图片与PDF文字识别敏感信息打码方案
前端·pdf·状态模式
打工仔折腾 AI2 小时前
LangChain 工具调用实战:从 Tool 定义到 Agent 执行链路拆解
java·前端·人工智能·后端·python·langchain·ai agent 实战
汉堡大王95272 小时前
单次输出拉到100万Token:拆完 Gemini 4 Argon 的续写协议,才看懂谷歌这7个月在憋什么
前端·人工智能·后端