支付宝小程序 | 上传图片组件(添加默认样式以及自定义上传样式)

发布时间 2023-05-25 20:42:20作者: 杨芋可可

使用my.uploadFile、 my.chooseImage 的方式实现图片上传

注意: 使用该方式上传文件,后端也需要参照官方文档进行修改

https://opendocs.alipay.com/mini/api/kmq4hc

一、展示效果

默认上传

demo4.gif

自定义上传

demo5.gif

二、上代码

(一)、上传组件

image.png

<view class="custom-upload-container">
  <view a:for="{{imageUrl}}" class="custom-upload images-show">
    <view class="clear" catchTap="handleDelete" data-url="{{item}}">
      <am-icon type="CloseCircleFill" color="#333333" size="x-small" />
    </view>
    <view a:if="{{item.status == 'fail' ? true : false}}" class="loading">
      <loading type="spin" size="small" text="上传中..." loading="{{true}}" />
    </view>
    <image
      mode="aspectFill"
      src={{item}}
      catchTap="hanldeImageLook"
      data-url="{{item}}"
      data-index="{{index}}"
    />
  </view>

  <view
    a:if="{{imageUrl.length < maxCount && imageUrl.length > 0 ? true:false}}"
    class="custom-upload "
  >
    <view class="add" catchTap="handleSelectImage">
      <am-icon type="AddOutline" color="#333333" size="small" />
    </view>
  </view>

  <view catchTap="handleSelectImage" style="width:100%">
    <slot a:if="{{ imageUrl.length == 0 ?true:false }}">
      <view class="default-upload">
        <am-icon type="AddOutline" color="#333333" size="small" />
      </view>
    </slot>
  </view>
</view>

upload-image.ts

Component({
  mixins: [],
  data: {
    imageUrl: [],
    maxCount: 1,
    action: '', //上传的url地址
  },
  props: {
    maxCount: 1,
    onUpload: (image, imageArr) => {},
    onDelete: (image, imageArr) => {},
    value: [],
    action: '',
  },
  didMount() {
    const maxCount = this.props?.maxCount || 1
    const value = this.props?.value || []
    const action =
      this.props?.action ||  'xxxxxxxx'
    this.setData({
      maxCount,
      imageUrl: value,
      action,
    })
  },
  didUpdate() {},
  didUnmount() {},
  methods: {
    handleSelectImage() {
      const { imageUrl, maxCount } = this.data
      if (imageUrl.length == maxCount) {
        my.showToast({
          content: `最多上传${maxCount}张图片`,
        })
        return
      }
      my.chooseImage({
        sourceType: ['camera', 'album'],
        count: 1,
        success: (res) => {
          const path = res.apFilePaths[0]
          const DeviceId = my.getStorageSync({ key: 'DeviceId' }).data
          const ACCESS_TOKEN = my.getStorageSync({ key: '__AT__' }).data
          const { account } = my.getStorageSync({ key: 'userinfo' }).data as any
          const { action } = this.data
          const SYSTEM_ID =
            (my.getStorageSync({ key: 'SyStemId' }).data as string)
          my.uploadFile({
            url: action,
            fileType: 'image',
            fileName: 'file',
            filePath: path,
            name: 'file',
            //请求头信息
            header: {
              DeviceId: DeviceId,
              uname: account,
              System: SYSTEM_ID,
            },
            success: (res) => {
              const value = JSON.parse(res.data)
              if (value?.code == 200) {
                const { imageUrl } = this.data
                const newImageUrl = imageUrl.concat(value?.data)
                this.setData({
                  imageUrl: newImageUrl,
                })
                this.props.onUpload(value?.data, newImageUrl)
              } else {
                my.showToast({
                  content: value?.msg || '上传失败',
                })
              }
            },
            fail: (err) => {
              my.showToast({
                content: '上传失败',
              })
              const { imageUrl } = this.data
              const newImageUrl = imageUrl.concat([])
              this.setData({
                imageUrl: newImageUrl,
                status: 'fail',
              })
            },
          })
        },
      })
    },
    handleDelete(e) {
      const { url } = e.currentTarget.dataset
      const { imageUrl } = this.data
      const newData = imageUrl.filter((i) => i !== url)
      this.setData({
        imageUrl: newData,
      })
      this.props.onDelete(index, newData)
    },
    hanldeImageLook(e) {
      const { imageUrl } = this.data
      const { index } = e.currentTarget.dataset
      my.previewImage({
        current: index, // 当前显示图片
        urls: imageUrl,
        success: (res) => {
          console.log('debug----res', res)
        },
        fail: (error) => {
          console.log('debug----error', error)
        },
      })
    },
  },
})

upload-image.less

.custom-upload-container {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  background: #ffffff;
  padding: 16px;
  border-radius: 8px;
  .custom-upload,
  .images-show {
    width: 80px;
    height: 80px;
    background: #ffffff;
    border: 1px dashed #979797;
    border-radius: 6px;
    display: flex;
    justify-content: center;
    align-items: center;
    position: relative;
    margin-right: 30px;
    .add {
      position: absolute;
      margin: auto;
    }
    .clear {
      position: absolute;
      top: 0;
      right: 0;
      margin-top: -6px;
      margin-right: -6px;
    }
    > image {
      width: 100%;
      height: 100%;
      border-radius: 4px;
      background: #fff;
    }
    .loading {
      position: absolute;
      margin: auto;
      width: 100%;
      height: 100%;
      background-color: rgba(0, 0, 0, 0.5);
      .amd-loading-spin-container {
        width: 100%;
        height: 100%;
      }
      .amd-loading-spin-text {
        color: #ffff;
      }
    }
  }
  .custom-upload:nth-of-type(3n) {
    margin-right: 0px;
  }
  .images-show {
    border: none;
  }

  .default-upload {
    width: 100%;
    height: 80px;
    border-radius: 4px;
    border: 1px dashed #979797;
    display: flex;
    justify-content: center;
    align-items: center;
    background: #ffffff;
  }
}

upload-image.json

    {
      "component": true,
      "usingComponents": {
        "am-icon": "antd-mini/es/Icon/index",
        "loading": "antd-mini/es/Loading/index"
      }
    }

(二)、在页面中引用组件

pageX.axml

//自定义上传样式
<upload-image
  maxCount="{{imgCount}}"
  value="{{imgValue}}"
  onUpload="handleUpload"
  onDelete="handleDelete"
>
  <view class="uplload-images">
    <text class="tip1">添加图片(非必传)</text>
    <text class="tip2">最多可以添加{{imgCount}}张图片</text>
  </view>
</upload-image>

//默认样式
<upload-image
  maxCount="{{imgCount}}"
  value="{{imgValue}}"
  onUpload="handleUpload"
  onDelete="handleDelete"
>
</upload-image>

pageX.less

.uplload-images {
  width: 100%;
  height: 80px;
  background: #ffffff;
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  .tip1 {
    font-size: 14px;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: #333333;
    line-height: 20px;
  }
  .tip2 {
    font-size: 12px;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: #999999;
    line-height: 16px;
    margin-top: 8px;
  }
}

pageX.json

{
  "defaultTitle": "上传图片",
  "usingComponents": {
       "upload-image":"/components/upload-image/upload-image" // 组件的路径
  }
}

pageX.ts

  data:{
    imgValue:[],
    imgCount:3,
   },
   handleUpload(file, fileList) {
      this.setData({
        imgValue: fileList,
      })
   },
    handleDelete(file, fileList) {
    const arr = []
    let { deleteImage } = this.data
    arr.push(file)
    const newImage = deleteImage.concat(arr)
    this.setData({
      imgValue: fileList,
      deleteImage: newImage,
    })
  },