微信小程序-上传多张图片加进度,持续修正中……

tips.参考网上资料的改进版

1.怎么使用.html

         <!-- 无限制需要在js代码里设置数量,upload为上传地址,或者说图片服务器 -->
          <up-pic url="{{upload}}" bindupImgData="upImgData" class='up-pic' notli/>
          <!-- 或者:限制只能少于9 -->
          <up-pic url="{{upload}}" bindupImgData="upImgData" count="8" class='up-pic'/>         

1.2.怎么使用.js

  // 上传图片返回
  upImgData(e) {
    // console.log(e.detail)
    this.setData({
      images: e.detail
    })
  },

1.3.怎么使用.json

{
  "usingComponents": {
    "up-pic": "./up-pic/index"
  }
}

2.核心组件代码

/up-ipc/

./up-ipc/index.js

/**
 * <up-pic url="{{upload}}" count="3" autoup class='up-pic'></up-pic>
 * 
 * url:上传图片地址
 * count:上传总数量(默认上传1张图片)
 * autoup:是否自动上传(无需传参数,参考以上)
 * 2019-04-15 MIT
 */
import { promisify } from '../../../../utils/promise'
const wxUploadFile = promisify(wx.uploadFile)
const network = require("../../../../utils/upload.js")
Component({

  data: {
    imgs: [],
    upload_picture_list: [],
    count: 1,
    url: '',
    notli: false
  },
  properties: {
    url: {
      type: String,
      observer(newVal, oldVal) {
        this.data.url = newVal;
      }
    },
    count: {
      type: Number,
      observer(newVal, oldVal) {
        this.data.count = newVal;
      }
    },
    notli: {
      type: Boolean
    }
  },

  methods: {
    chooseImage() {
      cImage(this, parseInt(this.data.count), this.data.url);
    },
    uploadimage() {
      uImage(this, this.data.url);
    },
    deleteImg(e) {
      dImage(e, this);
    },
    previewImg(e) {
      pImage(e, this);
    }
  }

})


// 上传图片(this,api.imageup)
const uImage = (_that, url) => {
  // console.log(_that.data.upload_picture_list)

  uploadFileServer(url, _that, _that.data.upload_picture_list)
}

const uploadFileServer = (url, that, upload_picture_list) => {
  const upload = promisify(network.upload)
  //上传

  const promises = upload_picture_list.map(function (item) {
    // console.log(item)
    if (item.path_server !== '') return;
    return upload({
      url: url,
      path: item['path'],
      name: 'file',
      extra: {},
      myfn (data) {
        item.path_server= data.result
        that.setData({
          upload_picture_list: upload_picture_list
        });
        let images = that.data.upload_picture_list.map(e => e.path_server)
        that.setData({
          images: images
        });
        that.triggerEvent('upImgData', images);
      },
      progress (res) {
        // console.log('上传进度', res.progress)
        item.upload_percent = res.progress
        that.setData({
          upload_picture_list: upload_picture_list
        });
      }
    })
  })
  
}


// 删除图片
const dImage = (e, _that) => {
  _that.data.upload_picture_list.splice(e.currentTarget.dataset.index, 1);
  _that.data.imgs.splice(e.currentTarget.dataset.index, 1);
  _that.setData({
    upload_picture_list: _that.data.upload_picture_list
  });
  let images = _that.data.upload_picture_list.map(e => e.path_server)
  _that.setData({
    images: images
  });
  _that.triggerEvent('upImgData', images);
}


// 选择图片
const cImage = (_that, count, url) => {
  wx.chooseImage({
    count: _that.data.notli ? count = 20 : count,
    sizeType: ['original', 'compressed'],
    sourceType: ['album', 'camera'],
    success: function(res) {
      _that.data.imgs = _that.data.imgs.concat(res.tempFilePaths)
      for (let i in res.tempFiles) {
        res.tempFiles[i]['upload_percent'] = 0
        res.tempFiles[i]['path_server'] = ''
        _that.data.upload_picture_list.push(res.tempFiles[i]);
        _that.data.upload_picture_list.length > count ? _that.data.upload_picture_list = _that.data.upload_picture_list.slice(0, count) : console.log();
      }
      !_that.data.notli && count == _that.data.upload_picture_list.length ? uImage(_that, url) : console.log();
      _that.data.notli && count == 20 ? uImage(_that, url) : console.log();
      _that.data.notli ? console.log(`%c 开启无限制上传图片模式(单次选择最多20张)`, `color:#f00;font-weight:bold;`) : console.log(`%c 开启限制上传图片模式,目标数量为:${count}`, `color:#f00;font-weight:bold;`);
      _that.data.upload_picture_list = _that.data.upload_picture_list.slice(0, count);
      _that.setData({
        upload_picture_list: _that.data.upload_picture_list,
      });
      // console.log(_that.data.upload_picture_list)
    }
  })
}

// 预览图片
const pImage = (e, _that) => {
  let percent = e.currentTarget.dataset.percent
  if (percent === '1') {
    wx.previewImage({
      current: _that.data.images[e.currentTarget.dataset.index],
      urls: _that.data.images
    })
  } else {
    wx.previewImage({
      current: _that.data.imgs[e.currentTarget.dataset.index],
      urls: _that.data.imgs
    })
  }
  
}

./up-ipc/index.json

{
  "component": true
}

./up-ipc/index.wxml

<view class='sunsin'>
  <view class="sunsin_picture_list">
    <view wx:for="{{upload_picture_list}}" class="sunsin_picture_item" wx:key="{{index}}">
      <image wx:if="{{item.upload_percent < 100}}" src="{{item.path}}" mode="aspectFill"></image>
      <image wx:if="{{item.upload_percent == 100}}"  data-index="{{index}}" src="{{item.path_server}}" mode="aspectFill" bindtap="previewImg" data-percent="1"></image>
      <view class="sunsin_upload_progress" wx:if="{{item.upload_percent < 100}}" data-index="{{index}}" bindtap="previewImg" data-percent="0">{{item.upload_percent}}%</view>
      <text class='del' bindtap='deleteImg' data-src='{{image}}'  data-index="{{index}}">×</text>
    </view>
    <view class='sunsin_picture_item' wx:if="{{upload_picture_list.length<count || notli}}">
      <view class="sunsin-add-image" bindtap='chooseImage'>
        <text class='iconfont icon-tupianshangchuan'></text>
      </view>
    </view>
  </view>
</view>

./up-ipc/index.wxss

@import "iconfont";

image {
  width: 40rpx;
  height: 40rpx;
  margin: 0 4%;
}

.icon-tupianshangchuan {
  font-size: 73rpx;
}

.sunsin_picture_list {
  width: 100%;
  padding: 20rpx;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  align-content: flex-start;
  flex-direction: row;
  justify-content: flex-start;
}

.sunsin_picture_list image {
  width: 40rpx;
  height: 40rpx;
  margin: 0 4%;
}

.sunsin-add-image {
  width: 150rpx;
  height: 150rpx;
  color: #ddd;
  font-size: 144rpx;
  line-height: 62%;
  text-align: center;
  margin: 2% 0 0 2%;
  background-color: #eee;
  cursor: pointer;
  border-radius: 10rpx;
}

.sunsin_picture_item {
  margin: 20rpx;
  margin-left: 0;
  position: relative;
  width: 160rpx;
  height: 160rpx;
}

.sunsin_picture_item .del {
  position: absolute;
  top: 0;
  right: -6rpx;
  color: #fff;
  border-radius: 4rpx;
  width: 40rpx;
  height: 40rpx;
  line-height: 40rpx;
  z-index: 2;
  text-align: center;
  background-color: #e54d42;
}

.sunsin_upload_progress {
  font-size: 24rpx;
  color: #fff;
  width: 167rpx;
  height: 160rpx;
  text-align: center;
  line-height: 160rpx;
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0.7;
  border-radius: 8rpx;
  background-color: #000;
}

.sunsin_picture_item image {
  width: 160rpx;
  height: 160rpx;
  border-radius: 3px;
}

.sunsin-yes-upload {
  color: #fff;
  border-radius: 0;
  background-color: #00a0e9;
}

./up-ipc/iconfont.wxss

@font-face {font-family: "iconfont";
  src: url('iconfont.eot?t=1552565213642'); /* IE9 */
  src: url('iconfont.eot?t=1552565213642#iefix') format('embedded-opentype'), /* IE6-IE8 */
  url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAANIAAsAAAAAB0AAAAL6AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCCcAqCQIIXATYCJAMICwYABCAFhG0HOhtHBhHVmz3IfibYjlEWYEvmdtInlWCZnjPBw2dX/arqwXWvwOwsL8yXn5lBjqcBAujAB8DmZugaFaFYkvO8n74jHRPS8MMn7p3+lvh8QDmOtWmsSV2A8daA9sYoobRAAvO4YeyCF3gbAtAJEEcMHT52KlY07EUCEGtXrViEtaBF60gXWBGYG3ZqiFxMWOUpeQfIiT4vvpKSFSQmhZ01cfmwpQz8UOVEqYO2g3MDAt5yZoDtAwXEAQ3E1EbreFQSiKPQ9YBGCI6VLuBDlc0WcA/7wwMBwoydageAH+Q+E8/jP2qRBEDj2QdXAtsnvRSYvBzt/bz2FJ92m1p4sC3DcwBFbU0dQvQryug45LG8oj6m/VpYYy9VD9Mzbk8/5FlSYmS0HSx1O92+wanxjJdWdjbcUTgUtwvToQ7DMaMNaajyc1uLMjxnTMswmiJXlBxqP+22dHpx4+z/oCz1YcxJ35OzZp3yDvEuDblmyAs4XltW5h3qfco2tr0lfVpba+cbf0vqRv+Etf3sSz2uWuyDvP5eckxa8IPaVP2gnlobNJBX0m6gvXS84Cjtawde0FPfrSz1Lj1+fPNmIWPi+/Yt80r1LgsP37ytZGJZTc0qKwMBsF1dUEF//jus3RfdusCx73+roQHwqHfp82iO7RoqCLDen03Af+YNbNAMga2TmsZrjEhWYrr/Mh0dsMFOFy+mKt1fyiywFngMEgv+UFgJI2m0OJgwSIMZKwOgE2vEfgNXm1EIrQ8Q4xiAwEkPJA6ch8LJXZJGew4THr7DjFMKOtOF64kGEZlBDCGUjAbUH4Ju1boGFnH6Hd2VJeUFEf2N1IMblnEuh29YkZZY0z9uZbZgqRXYwX2Yc4ODWkTNo2c+tmmyTU8adSuDMIRQMhqg/iDoVm3QmkXl/Xd0V5bUUVfnfCP1MDxYjOYBpJu0Dqp7lEf6x62YLbDUCtjBNMy5gaN5WkTNIz/Bd2wmp5kdKh23l5e/2wbobJXMGaVw2nUEWbv3XE77K9AMAwAA') format('woff2'),
  url('iconfont.woff?t=1552565213642') format('woff'),
  url('iconfont.ttf?t=1552565213642') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
  url('iconfont.svg?t=1552565213642#iconfont') format('svg'); /* iOS 4.1- */
}

.iconfont {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon-tupianshangchuan:before {
  content: "\e69d";
}

3.补充api封装

upload.js

function upload(options) {
  var url = options.url,
    path = options.path,
    name = options.name,
    // data = options.data,
    extra = options.extra,
    success = options.success,
    progress = options.progress, // progress 方法
    fail = options.fail,
    myfn = options.myfn
  const uploadTask = wx.uploadFile({
    url: url,
    filePath: path,
    name: name,
    formData: extra,
    success: function(res) {
      // console.log(res);
      var data = res.data
      try {
        data = JSON.parse(res.data)
        // console.log(data)
      } catch (e) {
        console.log(data)
        throw (e)
      }
      if (res.statusCode == 200) {
        if (success) {
          // console.log(data)
          success(data)
          myfn(data)
        }
      } else {
        if (fail) {
          fail(data)
        }
      }
    },
    fail: function(res) {
      console.log(res)
      if (fail) {
        fail(res)
      }
    }
  })

  uploadTask.onProgressUpdate((res) => {
    // console.log('上传进度', res.progress)
    // console.log('已经上传的数据长度', res.totalBytesSent)
    // console.log('预期需要上传的数据总长度', res.totalBytesExpectedToSend)
    if (progress)(
      progress(res)
    )
  })
}

module.exports = {
  upload: upload
}

promise.js

/**
 * 将wx的callback形式的API转换成支持Promise的形式
 */
module.exports = {

  promisify: api => {
    return (options, ...params) => {
      return new Promise((resolve, reject) => {
        const extras = {
          success: resolve,
          fail: reject
        }
        api({ ...options, ...extras }, ...params)
      })
    }
  }

}

4.demo