UniApp实现图片批量上传组件

5 阅读1分钟
<template>
  <view class="upload-container">
    <!-- 上传按钮 -->
    <view class="upload-btn" @click="selectFile">
      <uni-icons type="plusempty" size="24"></uni-icons>
      <text>上传图片</text>
    </view>

    <!-- 循环显示已上传的图片 -->
    <view class="upload-pic">
      <view v-for="(item, index) in imageList" :key="index" class="file-info">
        <img class="file-preview" :src="item.url" mode="aspectFit" />
        <view class="file-name">{{ item.name }}</view>
        <view class="delete-btn" @click="deleteFile(index)">
          <uni-icons type="trash" size="20" color="#ff0000"></uni-icons>
        </view>
      </view>
    </view>
  </view>
</template>

<script>
import constant from "@/constant/index.js"
export default {
  props: {
    label: String,
    value: {
      type: Array,
      default: () => [],
    },
    maxCount: {
      type: Number,
      default: 9,
    },
  },
  data() {
    return {
      imageList: [],
      myValue: [],
    }
  },
  watch: {
    value: {
      handler(newVal) {
        if (Array.isArray(newVal) && newVal.length > 0) {
          this.imageList = newVal.map((item) => ({
            url: `/wdxx/cos-appconfig/common/f3100202/file/${item}`,
            name: `${this.label || "file"}.jpg`,
          }))
          this.myValue = [...newVal]
        } else {
          this.imageList = []
          this.myValue = []
        }
      },
      immediate: true,
    },
  },
  methods: {
    selectFile() {
      // 调用实际的文件选择逻辑
      SystemUtils.postMessage(
        '{"type": "pickFileBase64","params":{},"callback": "handlePickFileBase64"}'
      )
      window.handlePickFileBase64 = this.handlePickFileBase64
    },

    async handlePickFileBase64(result) {
      if (!result) return

      const resultType = await this.$util.detectType(result)
      const allowedTypes = ["image/jpeg", "image/png", "image/gif"]

      if (!allowedTypes.includes(resultType)) {
        uni.showToast({
          icon: "none",
          title: "请上传图片格式文件",
          duration: 1500,
        })
        return
      }

      if (this.maxCount && this.imageList.length >= this.maxCount) {
        uni.showToast({
          icon: "none",
          title: `最多只能上传${this.maxCount}张图片`,
          duration: 1500,
        })
        return
      }

      const data = {
        name: `${this.label}`,
        suffix: resultType.split("/")[1],
        base64: result,
      }

      this.$http.post({
        url: constant.personNameSignUpload,
        data: data,
        success: (res) => {
          console.log(res, "cjc")

          // 添加新图片到列表
          const newImage = {
            url: `data:image/${data.suffix};base64,${result}`,
            name: `${this.label}.${data.suffix}`,
          }

          this.imageList.push(newImage)
          this.myValue.push(res.s00500)

          // 同步更新父组件的值
          this.$emit("input", [...this.myValue])
          this.$emit("update:value", [...this.myValue])
        },
        complete: (res) => {},
      })
    },

    deleteFile(index) {
      this.imageList.splice(index, 1)
      this.myValue.splice(index, 1)

      // 通知父组件值已更新
      this.$emit("input", [...this.myValue])
      this.$emit("update:value", [...this.myValue])
    },
  },
}
</script>

<style scoped lang="scss">
.upload-container {
  width: 100%;
  padding: 20rpx;
}

.upload-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 120px;
  height: 120px;
  border: 2px dashed #007AFF;
  border-radius: 8px;
  background-color: #F5F5F5;
  cursor: pointer;
}

.upload-btn text {
  margin-top: 10rpx;
  font-size: 28rpx;
  color: #007AFF;
}
.upload-pic{
  display: flex;
  flex-wrap: wrap;
  gap:10rpx;
  margin-top: 10rpx;
.file-info {
  position: relative;
  width: 100px;
  height: 100px;
  border: 2px solid #007AFF;
  border-radius: 8px;
  overflow: hidden;
}
}

.file-preview {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.file-name {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background-color: rgba(0, 0, 0, 0.7);
  color: white;
  padding: 5rpx;
  font-size: 24rpx;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.delete-btn {
  position: absolute;
  top: 0;
  right: 0;
  padding: 5rpx;
  border-radius: 50%;
  z-index: 10;
  background-color: rgba(255, 255, 255, 0.8);
}
</style>