支付宝小程序 | 自定义上传图片组件 (my.chooseImage + my.uploadFile)

541 阅读1分钟

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

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

opendocs.alipay.com/mini/api/km…

一、展示效果

动画.gif

二、上代码

(一)、上传组件

image.png

upload-image.axml


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

upload-image.ts

Component({
  mixins: [],
  data: {
    imageUrl: [], // 图片的url地址
    maxCount: 1,  //上传图片数量
    action: 'xxxxxx', // '上传文件的服务器地址'
  },
  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 ||  this.data.action
    this.setData({
      maxCount,
      imageUrl: value,
      action,
    })
  },
  methods: {
    handleSelectImage() {
      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
          my.uploadFile({
            url: action,
            fileType: 'image',
            fileName: 'file',
            filePath: path,
            //设置请求头信息
            header: {
              DeviceId: DeviceId,
              uname: account,
              System: 'xxxx', 
            },
            success: (res) => {
              const value = JSON.parse(res.data)
              if (value?.code == 200) {
                const { imageUrl } = this.data
                const newImageUrl = imageUrl.concat(value?.data) // value?.data 是后端接口返回的图片url地址
                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,
              })
            },
          })
        },
      })
    },
    handleDelete(e) {
      const { index } = e.currentTarget.dataset
      const { imageUrl } = this.data
      const newData = imageUrl.filter((i) => i !== index)
      this.setData({
        imageUrl: newData,
      })
      this.props.onDelete(index, newData)
    },
  },
})

upload-image.less

.upload-container {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  .upload {
    width: 80px;
    height: 80px;
    background: #f5f5f5;
    border-radius: 4px;
    display: flex;
    justify-content: center;
    align-items: center;
    position: relative;
    margin-right: 8px;
    margin-bottom: 8px;
    .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;
      }
    }
  }
}

upload-image.json

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

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

pageX.axml

<upload-image maxCount="{{9}}" onDelete="handleImageDelete" onUpload="hanldeImageUpload" value="{{imageValue}}" />

<view onTap="handleFinish">上传</view>

pageX.json

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

pageX.ts

data:{
  imageValue:[]
}
  async handleImageDelete(file, fileList) {
  //删除图片
  this.setData({
      imageValue: fileList,
    })
  },
  hanldeImageUpload(file, fileList) {
    //上传图片
    this.setData({
      imageValue: fileList,
    })
  },
  
  handleFinish(){
  console.log(this.imgValue)
}