微信小程序上传文件组件

微信小程序上传文件

一、说明

该拍照组件带有微信授权相机功能,会结合后端接口,将上传的图片以数组集合的形式传值给父级页面。
注意:组件适用于,单独上传图片,不携带参数,结合后端接口返回路径之后,再调用另外的保存接口,携带参数与图片提交的场景,请慎重使用。

支持功能

  • 相册&相机拍照
  • 可限制图片张数
  • 可根据自己需求新增删除功能
  • 可预览

缺陷

  • 目前不支持删除

二、原理

由于wx.uploadFile一次性上传多张图片会报错,只能一张张的上传,所以封装的上传文件组件结合后端接口进行的是循环上传。废话不多说了。

三、实现效果

四、具体实现

自定义组件uploadImageswen文件夹微信小程序自定上传文件下载地址,下面对文件四大部分进行说明

1、index.wxml

<view class='content'>
  <view class='img-list' wx:if="{{detailPics.length>0}}">
    <block wx:for="{{detailPics}}" wx:key="index">
        <image bindtap="previewImage" class='img-item' src='{{baseUrl+item}}' bindlongpress="bindlongpressimg" data-id='{{index}}'></image>
    </block>
  </view>
  <view class='chooseimg' wx:if="{{!isShow}}" bindtap='uploadDetailImage'>
    <view class="weui-uploader__input-box"></view>
  </view>
</view>

2、index.js

所有组件内的功能都附带注释,请耐心阅读

// component/uploadImages/index.js
import ipConfig from '../../../utils/ipConfig'   //   这里放有项目的baseUrl等其他配置,在这里主要用于拼接图片地址回显
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    count: {      //最多选择图片的张数,默认9张   在这里也同时作为总共可上传张数限制9张
      type: Number,
      value: 9
    },
    uploadUrl: { //图片上传的服务器路径,上传图片接口请求地址
      type: String,
      value: ''
    },
    isShow: {    // 隐藏上传按钮,在这里主要是在详情的时候遇到了
      type: Boolean
    },
    showUrl: {    //上传图片对象,指的是在父级页面你自定义的图片集合,用来存放每次上传图片的路径
      type: Array,
      value: [],
      observer: function (newVal) {  // 监听图片地址集合
        console.log(newVal)
        if (newVal == null||newVal.length===0) return;
        this.setData({
          detailPics:JSON.parse(JSON.stringify(newVal))
        })
      }
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    detailPics: [], //上传的结果图片集合
    isTakePhoto: false, // 是否有权限打开摄像头
    timer: null,   // 定时器
    // 由于是循环上传图片,总会有失败的情况,以下操作是为了记录每次上传图片的情况,并做出相应的反应
    isFault: 0, // 记录上传图片失败个数
    currRequestNum: 0, // 记录本次调用接口次数
    currSelectPicNum: 0,// 记录本次选择上传图片个数
    currUrl: [], //记录本次上传图片地址集合
    baseUrl:ipConfig.baseUrl   //  图片地址前缀
  },
  /**
   * 组件的方法列表
   */
  methods: {
    // 图片预览
    previewImage(e) {
      console.log(e)
      let array = []
      this.data.detailPics.forEach(item => {
        array.push(this.data.baseUrl+item)
      })
      wx.previewImage({
        current:array[e.currentTarget.dataset.id],
        urls: array,
      })
    },
    // 我的点击事件
    uploadDetailImage: function (e) { //这里是选取图片的方法
      var that = this;
      // 每次点击 重置本次选择上传图片个数、本次发起请求个数、本次上传图片故障数量、本次上传图片成功的地址集合
      that.setData({
        currSelectPicNum: 0,
        currRequestNum: 0,
        isFault: 0,
        currUrl:[]
      })
      //权限判断
      wx.getSetting({
        success(res) {
          if (!res.authSetting['scope.camera']) {
            wx.authorize({
              scope: 'scope.camera',
              success() {
                //直接打开摄像头  -第一次授权弹窗弹出,直接选择允许
                if (!that.data.isTakePhoto) {
                  that.getTakePhoto()  // 打开摄像头方法
                }
              },
              fail(err) {  //  第一次用户拒绝授权
                wx.showModal({
                  title: '提示',
                  content: '摄像头开启失败!!!',
                  cancelText: '退出',
                  confirmText: '去开启',
                  success(res) {
                    if (res.confirm) {
                      // 开启
                      wx.openSetting()  // 由于用户拒绝过授权开发摄像头,我们只能在设置中在此打开只用调用  openSetting
                    } else if (res.cancel) {
                      wx.navigateBack({
                        delta: -1,
                      })
                    }
                  }
                })
              }
            })
          } else {  //  已经授权过
            // 直接打开摄像头
            if (!that.data.isTakePhoto) {
              that.getTakePhoto()
            }
          }
        }
      })

    },
    // 打开摄像头方法
    getTakePhoto() {
      let that = this
      // 首先我们要判断当前图片地址集合是否超出我们的要求的个数
      if (that.data.count == that.data.detailPics.length) {
        wx.showToast({
          title: '至多上传' + that.data.count + '张图片',
          mask: true,
          duration: 500,
          icon:'error'
        })
        return false
      }
      wx.chooseImage({
        count: that.data.count-that.data.detailPics.length, // 每次最多可以选择的图片张数,默认9   每次上传图片的个数是=总限制数量-当前上传图片成功的地址集合的长度   保证总上传个数不会超出限制
        sizeType: ['original', 'compressed'], // original 原图,compressed 压缩图,默认二者都有
        sourceType: ['album', 'camera'], // album 从相册选图,camera 使用相机,默认二者都有
        success: function (res) {
          var imgs = res?.tempFilePaths || [];
          //  本次上传图片的个数记录
          that.setData({  
            currSelectPicNum:imgs.length
          })
          wx.showLoading({
            title: '上传中...',
            mask: true,
            icon:'loading'
          })
          imgs?.forEach(item => {  // 循环上传
          //   调用上传方法
            that.uploadimg({
              url: ipConfig.baseUrl + that.data.uploadUrl, //这里是你图片上传的接口
              path: item, //这里是选取的图片的地址数组
              header: {  // 请求头设置
                'content-type': 'application/x-www-form-urlencoded',
                'wx-token': wx.getStorageSync('Swrh_token'),
                "openId": wx.getStorageSync('Swrh_key').openId
              }
            });
          })
         
        },
      })
    },
    //多张图片上传
    uploadimg: function (data) {
      var that = this
      wx.uploadFile({
        url: data.url,
        filePath: data.path,
        name: 'file',    // 名字根据自己的接口文档定
        header: data.header,
        formData: {},
        success: (resp) => {
          var picUrl = JSON.parse(resp?.data || '{}') //返回的结果,可能不同项目结果不一样
          let currUrl = picUrl?.url || ''
          // 本次循环上传图片地址对象集合更新、本次循环上传图片发起请求个数记录
          that.data.currUrl.push(currUrl)
          that.setData({
            currUrl:that.data.currUrl,
            currRequestNum:that.data.currRequestNum+1
          })
        },
        fail: (res) => {
        // 由于本次循环可能也有失败的次数,所以请求次数也包含失败次数
          that.setData({
            isFault: this.data.isFault + 1,
            currRequestNum:that.data.currRequestNum+1
          })
        },
        complete: () => {  // 不管成功或者失败,都会执行的方法
        // 由于图片是循环上传,为了控制出现一次提示,只能等所有循环次数执行完毕进行提示
          if (that.data.currRequestNum === that.data.currSelectPicNum) {   //  当本次发起请求个数=本次选择图片个数时才会提示
            if (that.data.isFault>0) {
              wx.showModal({
                title: '温馨提示',
                content: '检测到有' + that.data.isFault + '张图片上传失败,可能需要您重新上传',
                showCancel: false,
                confirmText:'我知道了'
              })
            }else{
              wx.showToast({
                title: '图片上传成功',
                mask:true,
                icon:'success'
              })
            }
            let currArray = that.data.currUrl.concat(that.data.detailPics)  // 本次上传成功的图片地址集合与原有图片进行合并
            console.log(that.data.detailPics)
            that.setData({
              detailPics:currArray
            })
            that.triggerEvent('myevent', that.data.detailPics)//结果返回调用的页面
          }
        }
      });
    },

  }
})

3、index.json

大家都知道,这是组件的配置处

{
  "component": true,
  "usingComponents": {}
}

4、index.wxss


.content {
  width: 100%;
  border-radius: 10rpx;
}

.img-list {
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  margin-bottom: 10rpx;
}

.img-item {
  width: calc((100% - 30rpx) / 3);
  height: 174rpx;
  margin: 5rpx;
  background-color: #fff;
  border-radius: 4rpx;
}
/* 上传按钮 */
.chooseimg {
  width: 174rpx;
  height: 174rpx;
  background: #fff;
  border-radius: 4rpx;
  display: flex;
  justify-content: center;
  align-items: center;
}

.weui-uploader__input-box {
  width: 110rpx;
  height: 110rpx;
  font-size: 110rpx;
  text-align: center;
  line-height: 110rpx;
  position: relative;
}
.weui-uploader__input-box::after{
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  margin: auto;
  content: '';
  width: 1rpx;
  height: 100%;
  background-color: #d9d9d9;
}
.weui-uploader__input-box::before{
  content: '';
  width: 100%;
  height: 1rpx;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  margin: auto;
  position: absolute;
  background-color: #d9d9d9;
}

五、使用方法

1、json配置

直接在使用的页面的json配置文件中根据路径引入自定义组件,在这里我把他命名为uploadImages

{
  "navigationStyle": "custom",
  "usingComponents": {
    "uploadImages": "/pages/components/uploadImages"
  }
}

2、在使用页面的wxml中

<uploadImages style="flex:1" bindmyevent="myEventListener" count='{{countPic}}' showUrl="{{formData.imgUrl}}" uploadUrl="{{uploadImgUrl}}"></uploadImages>

uploadImages组件中存在着自定义事件myevent,父子组件直接通过自定义事件传参进行数据传输,
子组件的文件地址集合就是通过 triggerEvent向自定义组件myevent推送数据,在父组件中通过 myEventListener方法进行接收。
count:限制传输文件的个数
showUrl:定义在父组件中的文件地址集合变量
uploadUrl:传输文件的后端接口

3、js中

 data: {
    formData: {
      imgUrl: []
    },
    countPic: 9, //上传图片最大数量
    showImgUrl: "", //路径拼接,一般上传返回的都是文件名,
    uploadImgUrl: '/wechatApp/fireEye/imageUpload'  // 我的请求接口地址
  },
  methods:{
    //监听组件事件,返回的结果
  myEventListener: function (e) {
    let currLabel = `formData.imgUrl`
    let currArray = e.detail
    this.setData({
      [currLabel]: currArray
    })
  },
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值