小程序上传图片到七牛云(支持多张上传,预览,删除)

以下为wxml (使用的vant小程序ui框架,需在json文件里自行引入)<view class=‘clearFloat’> <view class=‘upload_title’>头像展示(必填) <span class=“basic_title_desc”>(选一张好看的个人照片可以增加客户点击的机会哦) </span> </view> <view class=‘healthCertImg’> <view class=‘imgrelative’ wx:if="{{headIconArr}}" wx:for="{{headIconArr}}" wx:for-index=“index” wx:for-item=“item” wx:key="this"> <image class=“image uploadimg” src="{{imgPath+item.key}}" mode=“aspectFit” id="{{imgPath+item.key}}" catchtap=‘previewHeadIcon’>{{item}}</image> <van-icon name=“clear” custom-style=“color:#979797;position:absolute;right:-20rpx;top:-20rpx;” id="{{index}}" bind:click=“deleteHeadIcon” /> </view> <image src=’../../imgs/upload.png’ class=‘uploadimg upload_jkz’ catchtap=‘headIcon’ wx:if="{{IsHeadIcon}}"></image> </view> </view>以下为wxss.clearFloat { clear: both; overflow: hidden;}.upload_title { color: #222; font-size: 32rpx; margin-bottom: 16rpx; display: block; margin-top: 50rpx;}.imgrelative { position: relative; height: 164rpx; width: 164rpx; margin-right: 43rpx; float: left;}.uploadimg { height: 164rpx; width: 164rpx; float: left;}以下为json{ “usingComponents”: { “van-popup”: “../../vant/popup/index”, “van-area”: “../../vant/area/index”, “van-icon”: “../../vant/icon/index”, “van-toast”: “../../vant/toast/index”, “van-datetime-picker”: “../../vant/datetime-picker/index”, “van-field”: “../../vant/field/index”, “upload”: “../../component/upload/index” }}以下为js文件(涉及到封装的微信ajax和七牛云上传图片方法在下面)const util = require(’../../utils/util.js’);const qiniuUploader = require("../../utils/qiniuUploader"); // 头像展示上传图片 headIcon() { var that = this that.chooesImage(that, 1, function(res) { that.data.headIconArr.push(res) // console.log(that.data.ysCertImgArr.length) if (that.data.headIconArr.length >= 1) { that.setData({ IsHeadIcon: false }); } that.setData({ headIconArr: that.data.headIconArr }); }) }, // 头像展示预览与删除 previewHeadIcon(e) { this._previewImage(e, this.data.headIconArr) }, deleteHeadIcon(e) { var that = this that._deleteImage(e, that.data.headIconArr, function(files) { that.setData({ headIconArr: files, IsHeadIcon: true }); }) }, /图片上传/ chooesImage(that, count, callback) { util.didPressChooesImage(that, count, function(filePath) { qiniuUploader.upload(filePath, (res) => { console.log(res) callback(res) that.checkSubmit() }, (error) => { console.error(’error: ’ + JSON.stringify(error)); }, null, // 可以使用上述参数,或者使用 null 作为参数占位符 (progress) => { // console.log(‘上传进度’, progress.progress) // console.log(‘已经上传的数据长度’, progress.totalBytesSent) // console.log(‘预期需要上传的数据总长度’, progress.totalBytesExpectedToSend) }, cancelTask => that.setData({ cancelTask }) ); }) },/图片预览/ _previewImage: function(e, arr) { var preUlrs = []; console.log(arr) const imgPath = ‘https://cdn.wutongdaojia.com/' arr.map( function(value, index) { var key = imgPath + value.key preUlrs.push(key); } ); wx.previewImage({ current: e.currentTarget.id, // 当前显示图片的http链接 urls: preUlrs // 需要预览的图片http链接列表 }) }, /图片删除/ _deleteImage: function(e, arr, callback) { var that = this; var files = arr; var index = e.currentTarget.dataset.index; //获取当前长按图片下标 console.log(index) wx.showModal({ title: ‘提示’, content: ‘确定要删除此图片吗?’, success: function(res) { if (res.confirm) { files.splice(index, 1); console.log(files) } else if (res.cancel) { return false; } // files, that.setData({ isCanAddFile: true }); that.checkSubmit() callback(files) } }) },以下为封装的七牛云上传图片方法(util.js)const qiniuUploader = require("./qiniuUploader");import api from ‘./api.js’;const getUploadToken = () => { var params = { token: wx.getStorageSync(’token’) } api.ajax(“GET”, params, “/weixin/getUploadToken”).then(res => { console.log(res.data) initQiniu(res.data) });}// 初始化七牛相关参数const initQiniu = (uptoken) => { var options = { region: ‘NCN’, // 华北区 // uptokenURL: ‘https://[yourserver.com]/api/uptoken’, // cdn.wutongdaojia.com // uptokenURL: ‘http://upload-z1.qiniup.com’, // uptokenURL: ‘https://yuesao.wutongdaojia.com/weixin/getUploadToken', // uptoken: ‘xxx’, uptoken: uptoken, // domain: ‘http://[yourBucketId].bkt.clouddn.com’, domain: ‘image.bkt.clouddn.com’, // image为七牛云后台创建的空间 shouldUseQiniuFileName: false }; qiniuUploader.init(options);}export function didPressChooesImage(that, count, callback) { getUploadToken(); // 微信 API 选文件 wx.chooseImage({ count: count, success: function(res) { console.log(res) var filePath = res.tempFilePaths[0]; console.log(filePath) callback(filePath) // 交给七牛上传 } })}/* * 文件上传 * 服务器端上传:http(s)://up.qiniup.com * 客户端上传: http(s)://upload.qiniup.com * cdn.wutongdaojia.com */function uploader(file, callback) { initQiniu(); qiniuUploader.upload(filePath, (res) => { // 每个文件上传成功后,处理相关的事情 // 其中 info 是文件上传成功后,服务端返回的json,形式如 // { // “hash”: “Fh8xVqod2MQ1mocfI4S4KpRL6D98”, // “key”: “gogopher.jpg” // } // 参考http://developer.qiniu.com/docs/v6/api/overview/up/response/simple-response.html that.setData({ ‘imageURL’: res.imageURL, }); }, (error) => { console.log(’error: ’ + error); }, // , { // region: ‘NCN’, // 华北区 // uptokenURL: ‘https://[yourserver.com]/api/uptoken’, // domain: ‘http://[yourBucketId].bkt.clouddn.com’, // shouldUseQiniuFileName: false // key: ’testKeyNameLSAKDKASJDHKAS’ // uptokenURL: ‘myServer.com/api/uptoken’ // } null, // 可以使用上述参数,或者使用 null 作为参数占位符 (res) => { console.log(‘上传进度’, res.progress) console.log(‘已经上传的数据长度’, res.totalBytesSent) console.log(‘预期需要上传的数据总长度’, res.totalBytesExpectedToSend) });};module.exports = { initQiniu: initQiniu, getUploadToken: getUploadToken, didPressChooesImage: didPressChooesImage}封装小程序wx.request(api.js)const ajax = (Type, params, url) => { var methonType = “application/json”; // var https = “http://www.wutongdaojia.com” var https = “https://yuesao.wutongdaojia.com” var st = new Date().getTime() if (Type == “POST”) { methonType = “application/x-www-form-urlencoded” } return new Promise(function (resolve, reject) { wx.request({ url: https + url, method: Type, data: params, header: { ‘content-type’: methonType, ‘Muses-Timestamp’: st, ‘version’: ‘v1.0’ // 版本号 // ‘Muses-Signature’: sign }, success: function (res) { // if (res.statusCode != 200) { // reject({ error: ‘服务器忙,请稍后重试’, code: 500 }); // return; // } // resolve(res.data); wx.hideLoading() console.log(res) if (res.data.status == 200) { resolve(res.data); } else if (res.data.status == 400) { wx.showToast({ title: res.data.message, icon: ’none’, duration: 1000 }) return } else if (res.data.status == 401){ wx.removeStorageSync(‘phone’) wx.removeStorageSync(’token’) wx.showToast({ title: res.data.message, icon: ’none’, duration: 1000, success:function(){ wx.navigateTo({ url: ‘../login/index’, }) } }) return } else { //错误信息处理 wx.showToast({ title: ‘服务器错误,请联系客服’, icon: ’none’, duration: 1000 }) } }, fail: function (res) { // fail调用接口失败 reject({ error: ‘网络错误’, code: 0 }); }, complete: function (res) { // complete } }) })}有什么不懂的可以加我微信(18310911617)备注(小程序上传图片到七牛云) ...

February 28, 2019 · 4 min · jiezi

react-native 上传图片和视频到阿里云, 带进度条

实现上面的效果需要的库如下react-native-image-pickerreact-native-progress先来说下是如何实现点击上传图标弹出optionModal上传选项的动画的.整个optionModal区域是一个Animated.View, render 的时候他的position 是 absolute的, 整个位置是隐藏在屏幕下的, bottom: - 200. 点击按钮之后,用Animated.spring 把 bottom 的值 调整到 0 , 这样隐藏的部分就弹出来了。const styles = StyleSheet.create({ container: { backgroundColor: theme.screen_background_color, zIndex: 100, height: 200, width: ‘100%’, position: ‘absolute’, bottom: - 200), backgroundColor: ‘rgb(255,255,255)’, alignItems: ‘center’, borderTopWidth: 1, borderTopColor: theme.divider_color, } showOptionModal() { Animated.spring( this.modalPos, { toValue: 0, } ).start();<Animated.View style={[styles.container, { bottom: this.modalPos }]}> </Animated.View>还有就是区域里面的upload video 和 upload photos 图标动画有个先后顺序,这里的处理就是upload video 这个图标用了个settimeout, 让他的动画触发晚了个 0.1秒而已。实现的方法也是跟optionModal弹出的方法一样。接下来就是选择手机里面的图片或者视频了,这里我们会用一个库叫做 react-native-image-picker, 这个库应该是大家很经常会使用到的, 就是选择手机里面的视频和图片,或者可以用摄像头拍摄图片. 当我们点击 upload photos 的时候, 触发下面的代码就可以开始选择图片了 ImagePicker.showImagePicker({ title: null, cancelButtonTitle: ‘cancel’, allowsEditing: true, chooseFromLibraryButtonTitle: ‘choose from camera roll’, takePhotoButtonTitle: type===‘video’?null:‘open camera’, mediaType: type, noData: true, quality: 0.5, videoQuality: ‘medium’, storageOptions: { skipBackup: true, cameraRoll: true, waitUntilSaved: true, }, }, (response) => { if (!response.didCancel && !response.error) { //可以在这里上传图片了 this.startUpload(response); } return null; }); }当图片选择完毕之后, 就会触发this.startUpload(response); 了, 下面就是如何处理图片上传阿里云的部分了。 在上传文件到阿里云oss 之前呢 需要从Oss获取几个配置项,OSSAccessKeyId,Signature,key, police, 可以看下Oss 文档,这个需要你自己搞定啦。startUpload(response){ const uploadMediaData = new FormData(); uploadMediaData.append(‘OSSAccessKeyId’, accessKeyId); uploadMediaData.append(‘policy’, policy); uploadMediaData.append(‘Signature’, signature); uploadMediaData.append(‘key’, key); uploadMediaData.append(‘success_action_status’, 201); uploadMediaData.append(‘file’, { uri: response.uri, type: ‘multipart/form-data’, name: response.fileName, }); // 上传成功 successResponse = (xhr) => { let returnKey = xhr.responseText.match(/<Key>([^<]*)</Key>/)[1]; //这个key 就是你上传文件在oss 的地址了, }; //上传失败 failResponse = () => { // to do }; //开始上传 const OSS_UPLOAD_URI = ‘http://xxxxx.oss-us-east-1.aliyuncs.com’ futch(OSS_UPLOAD_URI, { method: ‘POST’, body: uploadMediaData, extra: null, }, (progressEvent) => { // progress 就是上穿的进度, 更新 state 里面的uploadProgress const progress = (progressEvent.loaded / progressEvent.total); this.setState({ uploadProgress: progress, }) }, (xhr) => successResponse(xhr), failResponse) .then((res) => console.log(res), (err) => console.log(’error’ + err));}//这个方法就是具体上传的代码了futch = (url, opts = {}, onProgress, successResponse, failResponse) => { return new Promise((res, rej) => { let xhr = new XMLHttpRequest(); xhr.open(opts.method || ‘get’, url); for (let k in opts.headers || {}) xhr.setRequestHeader(k, opts.headers[k]); xhr.onload = e => res(e); xhr.onreadystatechange = (e) => { if (xhr.readyState !== 4) { return; } //阿里云的状态码201 才有返回的信息 if (xhr.status === 201) { xhr.extra = opts.extra; successResponse(xhr); } else { xhr.extra = opts.extra; failResponse(xhr); } }; xhr.onerror = rej; if (xhr.upload && onProgress) xhr.upload.onprogress = onProgress; xhr.setRequestHeader(‘Content-Type’, ‘multipart/form-data’); xhr.send(opts.body); });}如果一切都ok 的话, 这个时候在上传的过程中就应该出现进度条了,上面提到了,this.state.uploadProgress 是用来存储上传进度的, 我们就利用这个作为进度条的数据源了, 因为我们用的是圆形的进度条,这里需要另外一个库, ’ react-native-progress’.import ProgressCircle from ‘react-native-progress/Circle’;//render 的时候只要把this.state.uploadProgress 丢进去就行了 <ProgressCircle size={30} showsText={true} size={100} progress={uploadProgress} color={‘#32CDFF’} thickness={4} borderWidth={2} style={styles.progressCircle} />这里特别提出一下,oss 的上传成功的返回代码是201。这样整个过程就结束了, 其中有些细节没提出来,需要大家自己完善,但是大概的流程应该都写出来了. 希望对大大家有用。 ...

December 21, 2018 · 2 min · jiezi