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}}' style='display:{{isDel}}' 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