likes
comments
collection
share

封装一个支付宝小程序的upload文件上传组件!☀☀☀

作者站长头像
站长
· 阅读数 42

一、序言

上传图片以及大图预览应该是小程序中比较常用的api了,

但是很可惜,官方的mini-ali-ui并没有提供相关的ui组件

(微信常用的Vant-Weapp就提供了uploader文件上传组件,😵)

(不知道啥原因,2022年3月21日开始,mini-ali-ui将不再更新或升级,6月22日将下线相关文档⏰)

没办法,官方不提供,但是自己开发中又经常用到,所以咱们自己来快速封装一个简易的upload组件吧
支付宝小程序自定义组件的相关内容请参考官方文档:https://opendocs.alipay.com/m...

二、准备工作

主要的准备工作就两个

下载这两个图片!

😤😤😤

封装一个支付宝小程序的upload文件上传组件!☀☀☀封装一个支付宝小程序的upload文件上传组件!☀☀☀

三、实现

简单梳理一下需求:

⭐默认展示一个‘+’,点击的时候,可以让用户选择照片或者拍照

⭐需要一个图片url数组,按顺序展示数组中的图片,如果图片的数量小于最大上传数量,则在最后面显示‘+’号让用户继续上传

⭐图片右上角显示删除图标,点击之后返回图片在数组中的索引,在父组件自定义删除逻辑

⭐点击图片可大图预览

⭐上传成功之后返回图片的临时路径(本地路径),在父组件自定义自己的业务上传逻辑

PS:图片数组是由父组件传入的,不一定传入空数组,也可以传入已经存在图片url的数组。
  😏因此这个组件只要稍加改造,加一个参数emmm,就能变成一个缩略图预览组件。

PPS:(在实际应用中,小程序上的数据可能来源于一些pc平台的文件上传,这就可能导致后台返回的文件数组中存在一些pdf、word等其他格式的文件,支付宝小程序支持pdf文件查看,所以这里可以再优化一下✅)

话不多说,上代码


🅰upload.axml

<view class='view-row'>
  <!-- 如果图片的url为空 -->
  <block a:if="{{fileList.length === 0 && !onlyShow}}">
    <view class='upload' onTap='upFile'>
      <image class='view-half-full' src="/images/ic_pic_add.png" />
    </view>
  </block>
  
  <!-- 图片的url不为空 -->
  <block a:else>
    <!-- 首先按顺序渲染图片 -->
    <view class='flex-wrap'>
      <view class='upload' a:for="{{fileList}}" a:key="{{index}}">
        <image class='view-full' src="{{item}}" data-index="{{index}}" onTap='preViewImage' />
        <image a:if='{{!onlyShow}}' class='delete' src="/images/ic_pic_delete.png" data-index="{{index}}" onTap='deleteImage' />
      </view>
      
      <!-- 渲染上传图标 -->
      <view a:if='{{fileList.length < maxLength && !onlyShow}}' class='upload' onTap='upFile'>
        <image class='view-half-full' src="/images/ic_pic_add.png" />
      </view>
    </view>
  </block>
</view>

🅱upload.js

Component({
  mixins: [],
  data: {},
  props: {
    name: null,
    fileList: [], //显示的图片的url
    maxLength: 5, //上传图片的个数 默认为5
    onlyShow: false,// 是否仅仅展示图片,不显示上传及删除按钮
    sourceType: ['camera', 'album'],
    onActive: (res,name) => {
      console.log(res,name)
    },
    onDelete: (index,name) => {
      console.log(index,name)
    }
  },
  didMount() { },
  didUpdate() { },
  didUnmount() { },
  methods: {
    //选择文件
    upFile() {
      console.log('选择文件...')
      my.chooseImage({
        sourceType: this.props.sourceType,
        count: this.props.maxLength - this.props.fileList.length,
        success: res => {
          //直接抛出选择的图片的临时url数组,在父组件中处理相应上传业务
          this.props.onActive(res.apFilePaths, this.props.name)
        }
      })
    },
    //大图预览
    preViewImage(e) {
      let idx = e.currentTarget.dataset.index
      let url = this.props.fileList[idx]
      let itemType = url.split(".");
      let type = itemType[itemType.length - 1];
      if (type == 'word') {
        my.alert({
          content: '小程序暂时不支持显示word类型的文件'
        });
        return
      }
      if (type == 'pdf') {
        my.downloadFile({
          url: url,
          success({ apFilePath }) {
            my.openDocument({
              filePath: apFilePath,
              fileType: 'pdf',
              success: (res) => {
                console.log('open document success')
              },
            })

          },
          fail: () => {
            console.log('err')
          }
        })
        return
      }
      my.previewImage({
        current: 0,
        urls: [url]
      })
    },
    //点击删除图标的回调
    deleteImage(e) {
      let idx = e.currentTarget.dataset.index
      // 这里直接调用props中的onDelete钩子,将索引抛出,在父组件中处理删除的逻辑
      this.props.onDelete(idx, this.props.name)
    }
  },
});
两个image就是咱们第二部准备的两个图片😁
支付宝小程序api官方文档:https://opendocs.alipay.com/m...

最后就是样式了⛄

🆎upload.scss

.view-row {
  display: flex;
  flex-direction: row;
}

.flex-wrap{
  display: flex;
  flex-wrap: wrap;
}

.view-full{
  height:100%;
  wi

.view-half-full{
  height:50%;
  width:50%;
}

.upload{
  margin-right: 20rpx; 
  margin-bottom:20rpx;
  background:#e4e4e4;
  width:120rpx;
  height:120rpx;
  display: flex;
  justify-content: center;
  align-items: center;
  border-radius: 4rpx;
  position: relative;
}

.delete{
  position: absolute;
  top:-15rpx;
  left:105rpx;
  z-index: 99999;
  width:30rpx;
  height:30rpx;
}

四、使用示例

test.axml

<view>
  <upload 
      fileList="{{urlList}}" 
      maxLength="{{5}}" 
      name='urlList' 
      onActive="uploadSuccess" 
      onDelete='deleteImages'
>
</upload>
<view>

test.js

Page({
    data:{
        urlList:[]
    },
    ......
    uploadSuccess(resLocation, name){
       for(let i = 0;i < resLocation.length; i++){
           my.uploadFile({
             url : ...,
             header: requestUtil.createHeaders(),
             fileType: 'image',
             fileName: 'files',
             filePath: resLocation[i],
             success:res => {
                 //更新urlList
             },
             fail:() => {},
             complete:() => {}
         })
      }
    },
    deleteImages(idx, name) {
        console.log('删除图片', idx)
        let urlList = this.data[name]
        urlList.splice(idx, 1)
        this.setData({
        [name]: urlList,
    })
  },
})
上传文件的api可以查看支付宝小程序官方档:https://opendocs.alipay.com/m...
🌈默认状态

封装一个支付宝小程序的upload文件上传组件!☀☀☀

🌈上传成功

封装一个支付宝小程序的upload文件上传组件!☀☀☀

🌈仅用作缩略图

封装一个支付宝小程序的upload文件上传组件!☀☀☀

🌈大图预览

封装一个支付宝小程序的upload文件上传组件!☀☀☀

🌈pdf预览

封装一个支付宝小程序的upload文件上传组件!☀☀☀

Props

参数说明类型默认值
name标识符,可在钩子函数参数第二项获取String、Numbernull
fileList图片url数组Array[]
maxLength最大上传数量Number5
onlyShow是否仅用于图片展示booleanfalse
sourceType上传图片的类型,默认同时支持选择摄像头和本地图片选择[]['camera', 'album']
onActive上传成功时的钩子,第一个参数为本次选择图片的临时路径数组,第二个参数为nameFunction(res,name) => {console.log(res,name)}
onDelete点击删除时的钩子,第一个图片在fileList中的索引,第二个参数为nameFunction(res,name) => {console.log(res,name)}

完 祝平安🍻