记录———封装uni-app+vant(u-upload)上传图片组件

上传图片回显,自定义图片回显样式

这段代码是一个Vue组件,主要实现了图片上传和预览的功能。组件接收了父组件传递的图片列表、最大图片数量和上传状态等属性。在模板中,使用了uni-easyinput组件和u-upload组件来实现图片上传和预览功能。在方法中,实现了删除图片、上传图片和预览图片的逻辑。整体功能包括图片上传、预览、删除和限制最大图片数量等。

父组件使用:
parentImgList中传入的值双向,子组件更新则父组件更新,是图片URL数组

isUploading是当前是否正在上传中

复制代码
<upload-image :parentImgList.sync="form.imgList" :isUploading.sync="isUploading"></upload-image>

组件内容

复制代码
<template>
  <view>
    <view class="photo-box flex-row">
      <view class="photo" v-for="(item, index) in imgList" :key="index">
        <view class="delete-btn" @click="deletePhoto(index, 'after')">
          <img src="@/assets/icon/delete.svg" />
        </view>
        <view class="photo-image" @click="viewImage(item)">
          <img :src="item" />
        </view>
      </view>
      <!-- v-bind="$attrs" 接收父组件的传值,并赋给<u-upload>;
	某一属性如果子组件(本组件)已经设值,子组件的值覆盖父组件的;
	以maxCount属性为例,这里设了5,那么不管父组件传多少,实际用的值一直是5。 -->
      <u-upload
        v-bind="$attrs"
        :maxCount="maxCount"
        name="fileList"
        uploadIcon="plus"
        width="110"
        height="110"
        :previewFullImage="true"
        multiple
        @afterRead="handleAfterRead"
        @delete="deletePic"
        v-if="!isUpload && imgList.length < 6"
      >
        <view class="upload-content">
          <u-icon name="plus" color="#6E9CFE" size="20"></u-icon>
        </view>
      </u-upload>
      <view class="upload-content" v-if="isUpload && imgList.length < 6">{{ isUpload }}</view>
    </view>
    <view style="color: #999;font-size: 9px;margin-top: 2px;">最多上传六张</view>
    <!-- 模态框显示大图 -->
    <view v-if="showModal" class="modal" @click="showModal = false">
      <img :src="currentImage" class="modal-image" />
    </view>
    <van-overlay :show="isUploading">
      <van-loading size="35px">图片上传中...</van-loading>
    </van-overlay>
  </view>
</template>

<script>
import { photoUploadFileAPI } from "@/api/upload.js"; // 与后端商量好的上传图片接口,使用 uni.uploadFile
import { Loading, Notify  } from 'vant-green'; // vant的组件
export default {
  name: "img-upload",
  props: {
    parentImgList: {
      type: Array,
      default: () => {
        return [];
      },
    },
    maxCount: {
      type: Number,
      default: 6,
    },
    isUploading: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      fileList: [],
      imgList: [],
      showModal: false,
      currentImage: "",
      isUpload: '',
      chooseImgNumber: 0
    };
  },
  watch: {
    parentImgList: {
      handler(val) {
        // console.log("父组件传递的数据", val);
        if (val) {
          this.imgList = val;
        }
      },
      deep: true,
    },
    imgList(val) {
      // console.log("女此案你看见", val);
      this.$emit("update:parentImgList", val);
    },
  },
  mounted() {
    console.log("fileList", this.value);
  },

  methods: {
    // s删除修改状态下原本有的照片
    deletePhoto(index) {
      this.imgList.splice(index, 1);
      console.log(`点击删除序号为${index}的照片`, this.imgList);
    },
    // 新增图片
    async handleAfterRead(event) {
      // 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
      this.chooseImgNumber++
      this.$emit('update:isUploading', true)
      let lists = [].concat(event.file);
      console.log('上传的图片', lists, lists.length, event.file)
      this.isUpload = '上传中...'
      for (let i = 0; i < lists.length; i++) {
        if (this.imgList.length < 6) {
          const result = await photoUploadFileAPI(lists[i].url);
          console.log("result>>>图片上传结果", result);
          if (result.success) {
            this.imgList.push(result.data);
            this.chooseImgNumber--
          } else {
            Notify({ type: 'danger', message: '图片上传失败' });
          }
        } else {
          Notify({ type: 'warning', message: '最多上传6张图片' })
        }
      }
      this.isUpload = ''
      this.$emit('update:isUploading', false)
      // console.log("fileList2", this.fileList, this.imgList, this.chooseImgNumber);
      // this.$emit('input', this.imgList);
    },
    viewImage(image) {
      this.currentImage = image;
      this.showModal = true;
    },
  },
};
</script>

<style lang="scss" scoped>
.photo-box {
  margin-right: 10px;
  flex-wrap: wrap;

  .photo {
    position: relative;

    .photo-image {
      width: 95px;
      height: 95px;
      margin-right: 10px;
      margin-bottom: 5px;

      img {
        width: 100%;
        /* 使图片宽度填满容器 */
        height: 100%;
        /* 使图片高度填满容器 */
        object-fit: cover;
        /* 保持比例并裁剪 */
        border-radius: 4px;
      }
    }

    .delete-btn {
      position: absolute;
      right: 8px;
      top: 0;
      background-color: rgba($color: #000000, $alpha: 0.1);
      width: 18px;
      border-radius: 20px;
      height: 18px;
      // font-size: 40rpx;
      text-align: center;
      // line-height: 50rpx;
      color: #555;
    }
  }
}

.modal {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.8);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 99999999999;
}

.modal-image {
  max-width: 90%;
  max-height: 90%;
}

.upload-content {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100px;
  height: 102px;
  border-radius: 3px;
  margin-top: 1px;
  border: 1px dashed #5a9fff;
  // background: #f4f8ff;
  box-sizing: border-box;
}
</style>
<style>
.van-loading, .van-loading__spinner {
  /* margin-top: 45%; */
}
.van-overlay {
  padding-top: 45vh;
  text-align: center;
}
</style>
相关推荐
非优秀程序员6 小时前
第04章 邮箱大战,163 与 QQ 的暗战|《互联网产品恩仇录》
java·vue.js·架构
tryCbest13 小时前
Vue系列——第 15 篇:内置组件全家桶——Transition、Teleport、Suspense、KeepAlive
前端·vue.js
徐小夕17 小时前
开源Vector-Graph-RAG:向量+图谱双引擎,打破纯向量RAG的效果天花板
前端·vue.js·github
FungLeo20 小时前
成为全栈·Vue 管理后台篇·Vue3 + Vite + Naive UI:后台工程基座怎么搭
前端·vue.js·ui·typescript·vite·前端工程化·biome
FungLeo21 小时前
成为全栈·Vue管理后台篇·<scriptsetup>:把页面拆成可读、可测的 Vue 组件
前端·javascript·vue.js·typescript·前端组件化·composition api·vue sfc
软件技术NINI2 天前
基于SpringBoot和Vue的新能源汽车销售推荐系统
java·vue.js·spring boot·后端·汽车·毕业设计·毕设
招风的黑耳2 天前
SpringBoot+Vue+MySQL 民宿在线预定平台 完整可运行版(源码+文档)
vue.js·spring boot·mysql
10share3 天前
基于大模型的 i18n 方案:把中文原文当 Key,轻松搞定多语言维护
前端·vue.js
啾咪orJIUMI3 天前
Vue 3 + 高德地图封装实战:点位、区域、Loca 流光与 Vue 信息窗体
前端·vue.js
FRing033 天前
vue2干货总结8(路由模块封装、router-link、声明式导航、路由重定向、编程式导航)
开发语言·前端·vue.js·vue2