上传图片分别有uni.uploadFile方法和base64方法,后端用nodejs作服务。

  1. uni.uploadFile方法,前端只负责上传图片,后端接收图片后进行压缩保存。(H5,安卓能正常使用)
  2. base64方法,前端先压缩图片和转换成base64再上传,后端只接收保存。(安卓不能上传图片)

uni.uploadFile方法

  1. 前端uniapp代码
<template>
	<view>
		<view class='pages'>
		  
			<view class='father_view'> 
				<view class='son_view'> 
				  <view class="title-bg">想说就说(最多120个汉字)</view>
				  <textarea class="textarea-bg" v-model="text1" @blur="inputText"  placeholder="请输入留言" /> 
				</view> 
			</view>
			
			<!-- 图片 -->
			<view class="images_box">
				<block v-for="(item, index) in imglist" :key="index">
				  <view class='img-box'>
					<image class='img' :src='item' mode='aspectFill'></image>
					<view class='img-delete' @click='imgDelete1' :data-delindex="index">
					    <image class='img' src='../../static/delect.png' ></image>  
					</view>
				  </view>
				</block>
				<view class='img-box' @click='addPic1' v-if="imglist.length<9">
					<image class='img' src='../../static/add_image.png'></image>  
				</view>
			</view>
			
			<button @click='uploadimage'>上传图片</button>			
			<button @click='viewmemo'>查看留言</button>
		</view>		
	</view>	
</template>

<script>
	export default {
		data() {
			return {
				imglist:[],//选择图片后生成的临时地址数组
				text1:'',
				imglist00:[]
			}
		},
		
		onLoad() {	},
		
		methods: {	
			//*获取文本框内容*//
			inputText:function (e) {
				this.text1 = e.detail.value	
			},
			
			//*选择图片*//
			addPic1: async function() {
				let that = this				
				uni.chooseImage({
					count: 9,  // 最多可以选择的图片张数,默认9
					sizeType: ['compressed'], // original 原图,compressed 压缩图,默认二者都有
					sourceType: ['album', 'camera'], // album 从相册选图,camera 使用相机,默认二者都有
				    success: function (res) {						
						if (that.imglist.length === 0) {
							that.imglist = res.tempFilePaths
						} else if (that.imglist.length < 9) {
							that.imglist = that.imglist.concat(res.tempFilePaths); //concat追加到数组
						}
					}
				})
			},
			
			//*显示选择后的图片*//
			imgbox: function (e) {				
			    this.imglist = e.detail.value
			},
			
			//* 删除已经选择的图片 *//
			imgDelete1: function (e) {				
				let index = e.currentTarget.dataset.delindex; //获取要删除的图片的下标,否则删除的永远是第一张 ,对应 <view class='img-delect' @click='imgDelete1' :data-delindex="index">
				this.imglist.splice(index, 1);			  	
			},
			
			//*上传图片*//
			uploadimage: function () {
				let app = getApp()
				let that = this
				let upimg = require("./upimg.js") //引用当前目录下的自定义函数
				let text2 = that.text1
				
				if (text2 == '') {
					uni.showToast({  //显示对话框
						title: "请输入留言!",
						icon: 'none',
						duration: 1000,
					});
				} else {	
					if (that.imglist.length != 0 ) { //数组不为空的时候才执行 				
						upimg.uploadimg({ //********* 调用引入的upimg.js文件uploadimg函数 ************
							url: app.globalData.url+'/imgup', //全局变量,后端接口地址
							path: that.imglist, //选取图片的临时地址数组 
							text: that.text1,  //文本框内容  
							user: app.globalData.username, 
						});
						uni.showToast({  //显示对话框
							title: "上传中!",
							icon: 'loading',
							duration: 3000,
						});					
						setTimeout(function () { //延迟执行,目的是等待上一步的uploadimg函数执行完成赋值给全局变量后再执行下面的代码
							that.imglist = []  //清空选择的图片
							that.text1 = ''   //清空文本框的内容						
						}, 1000); //延迟时间
					 
					} else {
						uni.showToast({
						  title: "请添加图片!",
						  icon: 'none',
						  duration: 1000,
						})
					}
				}
			},
			
			viewmemo:function (e) {
				uni.navigateTo({  //跳转到指定页面
					url: "../memo/memo",
				})
			}
		},
	}
</script>

<style>
	@import "./imgup.css";
</style>

多图上传函数 upimg.js 代码


//多张图片上传
function uploadimg(data) {
  var app = getApp()
  var imgurln=[]	
  var that = this
  
  i = data.i ? data.i : 0,  //当前上传的哪张图片
  success = data.success ? data.success : 0,  //上传成功的个数
  fail = data.fail ? data.fail : 0;  //上传失败的个数
  uni.uploadFile({
		url: data.url, //从调用页面传入 -- url: 'http://127.0.0.1:3000/' 后端接口地址
		filePath: data.path[i], //从调用页面传入 --path: imgbox, 选取图片的地址数组  
		name: 'img', //文件名称可以自定义,要与后端配对使用:app.post('/',upload.single('img'),function(req,res,next)
		formData: {  //这里是上传图片时一起上传的数据
			user: data.user,
			memo: data.text   //从调用页面传入 -- text:text1 文本框内容  
		},

		success: (resp) => {
			success++;//图片上传成功,图片上传成功的变量+1
			//console.log(resp.data) //在调试窗口显示后端返回的图片名称      
			imgurln = imgurln.concat(app.globalData.url + resp.data); //以图片名称拼接成网址,并追加到数组imgurln
		},

		fail: (res) => {  //失败
			fail++;//图片上传失败,图片上传失败的变量+1
			console.log('fail:' + i + "fail:" + fail);
		},

		complete: () => { //不论成功、失败都执行		
			i++; //这个图片执行完上传后,开始上传下一张
			if (i == data.path.length) {   //当图片传完时,停止调用				
				console.log('1>'+app.globalData.url);       
				console.log('执行完毕');
				console.log('成功:' + success + " 失败:" + fail);
			} else { //若图片还没有传完,则继续调用函数
				//console.log(i);
				data.i = i;
				data.success = success;
				data.fail = fail;
				that.uploadimg(data);
			}
		}
    });
}

module.exports.uploadimg = uploadimg; //把uploadimg函数暴露,才能在其它js文件引用此函数。 

遍历数组方式上传多图更简单,不必再调用自定义多图上传函数。
在这里插入图片描述

`

  1. 后端nodejs代码
var express=require('express')
var app=express()
var router=express.Router()
var multer=require('multer')
var path=require('path')
var image = require("imageinfo")
var mssql =require("mssql")  //引用mssql
var config = require('../config.js') //引用config.js文件
var request = require("request")
	
var storage = multer.diskStorage({ 
    destination: function (req, file, cb) {
        cb(null, 'public/imgtemp/');  	// 接收到文件后的保存路径,需要手动创建  
    },
    filename: function (req, file, cb) { 
		cb(null, Date.now() + "-" + file.originalname);  // 将保存文件名设置为: 时间戳 + 文件原始名,比如 151342376785-123.jpg
	}
});
var upload = multer({ storage: storage })
var type = upload.single('img')  //与前端的name:'img'对应

//* 接收图片 *//
router.post('/',type,function(req,res,next){
	console.log('01>>',req.file);
	console.log('02>>',req.body);
	//console.log('03>>',req.file.path);
	res.send(req.file.filename); //向前端返回当前上传成功的文件名	
	
	mssql.connect(config, function (err) {  //连接数据库
	    if (err) {
			console.log('数据库连接失败')
			return callback(err);			  
		} else {
			//console.log('数据库连接成功')		    		        
			var user1 = req.body.user ;
			var memo1 = req.body.memo ;  //req.body 解析前端formdata传递过来的数据 //req.query 解析前端data传递过来的数据
			var filename1 = req.file.filename ;
			var request = new mssql.Request();
			request.query("INSERT INTO wx_bbs (username,memo,filename) VALUES ('"+ user1 +"','"+ memo1 +"','"+ filename1 +"')",function (err, recordsets,returnValue) {
				if (err) {
					console.log(err);
					return
				} else {		
					//str = JSON.stringify(recordsets.recordset); //将查询结果转换成json格式
					//res.send(str);  //响应请求,将数据发送到前端
					console.log('执行sql脚本成功');  //在调试窗口显示
				}
			})
		};
		
		mssql.end;  //结束连接数据库
	});	

	// 压缩图片并删除原图 //
	var images = require("images")
	var fs=require('fs') 
	var name = './public/imgtemp/' + req.file.filename;  	//原图像文件完整路径
	var outName = './public/imgup/' + req.file.filename;	//压缩后的图像文件完整路径
	
	images(name)				   					  //加载原图像文件
	  .size(1000)					  				  //等比缩放图像到1000像素宽
	  .draw(images("./public/png/logo.png"), 10, 10)  //在(10,10)处绘制Logo
	  .save(outName, {quality:60})  				  //保存图片到文件,图片质量为60%
	
	fs.unlink(name,function(err){  	//删除原图
		if(err){								
			console.log('删除失败');
			return;
		}							
		console.log('原图删除成功');
	})	
})

module.exports = router;  //暴露模块,其它地方才能调用此模块

base64方法

  1. 前端uniapp代码
<template>
	<view>
		<view class='pages'>		  
			<view class='father_view'> 
				<view class='son_view'> 
				  <view class="title-bg">想说就说(最多120个汉字)</view>
				  <textarea class="textarea-bg" v-model="text1" @blur="inputText"  placeholder="请输入留言" /> 
				</view> 
			</view>
			
			<!-- 图片 -->
			<view class="images_box">				
				<block v-for="(item, index) in imagearr" :key="index">
				  <view class='img-box'>
					<image class='img' :src='item' mode='aspectFill'></image>
					<view class='img-delete' @click='imgDelete1' :data-delindex="index">
					    <image class='img' src='../../static/delect.png' ></image>  
					</view>
				  </view>
				</block>
				<view class='img-box' @click='addPic1' v-if="imagearr.length<9">
					<image class='img' src='../../static/add_image.png'></image>  
				</view>
			</view>
			
			<button @click='uploadimage'>上传图片</button>			
			<button @click='viewmemo'>查看留言</button>
		</view>		
	</view>	
</template>

<script>	
	export default {		
		data() {
			return {				
				imagearr: [],
				text1:''
			}
		},	
		
		methods: {	

			// 获取文本框内容
			inputText:function (e) {				
				var app = getApp()
				app.globalData.memo = e.detail.value
				this.text1 = e.detail.value
			},
			
			// 选择图片
			addPic1: async function() {
				let that = this
				uni.chooseImage({
					count: 9,
					sizeType: ['original', 'compressed'],
					sourceType: ['album','camera'],
					success: (res) => {
						if (that.imagearr.length === 0) {
							that.imagearr = res.tempFilePaths							
						} else if (that.imagearr.length < 9) {
							that.imagearr = that.imagearr.concat(res.tempFilePaths); //concat追加到数组
						}				
					}
				});
			},
			
			// 上传图片
			uploadimage: function () {				
				let that = this				
				let text2 = that.text1				
				if (text2 == '') {
					uni.showToast({  //显示对话框
						title: "请输入留言!",
						icon: 'none',
						duration: 1000,
					});
				} else {	
					if (that.imagearr.length != 0 ) { //数组不为空的时候才执行						
						that.imgCompress(that.imagearr) //调用函数imgCompress				
						setTimeout(function () { //延迟执行
							that.imagearr = []  //清空选择的图片
							that.text1 = ''   //清空文本框的内容						
						}, 3000); //延迟时间
						
						uni.showToast({  //显示对话框
							title: "上传中!",
							icon: 'loading',
							duration: 3000,
						});	
					 
					} else {
						uni.showToast({
						  title: "请添加图片!",
						  icon: 'none',
						  duration: 1000,
						})
					}
				}
			},

		    // 循环调用压缩图片
			imgCompress(tempFilePaths) {
				let compressImgs = [];
				let results = [];
				tempFilePaths.forEach((item, index) => {
					compressImgs.push(new Promise((resolve, reject) => {
						// #ifndef H5
						uni.compressImage({
							src: item,
							quality: this.quality,
							success: res => {
								//console.log('compressImage', res.tempFilePath)
								results.push(res.tempFilePath);
								resolve(res.tempFilePath);
							},
							fail: (err) => {
								//console.log(err.errMsg);
								reject(err);
							},
							complete: () => {
								//uni.hideLoading();
							}
						})
						// #endif
						// #ifdef H5				
						//调用压缩图片函数 canvasDataURL
						this.canvasDataURL(item, {  
							quality: this.quality / 100
						}, (base64Codes) => {
							//this.imgUpload(base64Codes);
							results.push(base64Codes);
							resolve(base64Codes);
						})
						// #endif
					}))
				})
				Promise.all(compressImgs) //执行所有需请求的接口
				.then((results) => {
					//uni.hideLoading();
					//this.imgUpload(results);
				})
				.catch((res, object) => {
					//uni.hideLoading();
				});
			},
			
			//压缩图片
			canvasDataURL(path, obj, callback) {				
				var img = new Image();
				img.src = path;
				img.onload = function() {
					var that = this;
					// 默认按比例压缩
					var w = that.width,
						h = that.height,
						scale = w / h;
					w = obj.width || w;
					h = obj.height || (w / scale);
					
					var quality = 0.3; // 图片质量 quality值越小,所绘制出的图像越模糊
					//生成canvas
					var canvas = document.createElement('canvas');
					var ctx = canvas.getContext('2d');
					// 创建属性节点
					var anw = document.createAttribute("width");
					anw.nodeValue = w;
					var anh = document.createAttribute("height");
					anh.nodeValue = h;
					canvas.setAttributeNode(anw);
					canvas.setAttributeNode(anh);
					ctx.drawImage(that, 0, 0, w, h);
					
					if (obj.quality && obj.quality <= 1 && obj.quality > 0) {
						quality = obj.quality;
					}

					var base64 = canvas.toDataURL('image/jpeg', quality);					
					callback(base64);  // 回调函数返回base64的值
					//console.log(base64);
					
					var app = getApp()
					var user = app.globalData.username;
					var url = app.globalData.url;
					var memo = app.globalData.memo;
					//向后端上传数据
					uni.request({						
						url: url+'/imgup',
						data: {        
							img64: base64 ,
							user: user ,
							memo: memo 
						},
						method: 'POST',
						header: { 'content-type': 'application/json' },
						success: (res) => {  //请求成功
						    console.log(res.data)  //在设计调试窗口显示后端返回的结果	
						},
						fail: () => {
							
						},
						complete: () => {
							
						}
					})
				}
			},
			
			// 删除已经选择的图片
			imgDelete1: function (e) {				
				let index = e.currentTarget.dataset.delindex; 
				//获取要删除的图片的下标,否则删除的永远是第一张 ,对应 <view class='img-delect' @click='imgDelete1' :data-delindex="index">
				this.imagearr.splice(index, 1);			  	
			},
			
			// 查看留言
			viewmemo:function (e) {
				uni.navigateTo({  //跳转到指定页面
					url: "../memo/memo",
				})
			}
		},
	}
</script>

<style>
	@import "./imgup.css";
</style>

  1. 后端nodejs代码
var express=require('express')
var app=express()
var router=express.Router()
var mssql =require("mssql")  //引用mssql
var config = require('../config.js') //引用config.js文件
var fs=require('fs') 

//* 接收图片 *//
router.post('/',function(req,res) {	
	var user1 = req.body.user ;
	var memo1 = req.body.memo ; 
	var imgdata = req.body.img64 ; //接收前端POST过来的base64
	var base64Data = imgdata.replace(/^data:image\/\w+;base64,/, "");  //过滤 data:image/jpeg;base64,
	var dataBuffer = new Buffer(base64Data, 'base64');
	
	var save_path = './public/imgup/'  //保存路径
	var file_name = Date.now() + '.png'  //以时间戳做文件名
	var save_name = save_path + file_name
	
	fs.writeFile(save_name, dataBuffer, function(err) {
		if(err){
		  res.send(err);
		}else{
		  res.send("后端图片保存成功!");
		  console.log("保存成功!")
		}
	});	
	
	mssql.connect(config, function (err) {  //连接数据库
	    if (err) {
			console.log('数据库连接失败')
			return callback(err);			  
		} else {
			//console.log('数据库连接成功')		
			var request = new mssql.Request();
			request.query("INSERT INTO wx_bbs (username,memo,filename) VALUES ('"+ user1 +"','"+ memo1 +"','"+ file_name +"')",function (err, recordsets,returnValue) {
				if (err) {
					console.log(err);
					return
				} else {		
					//str = JSON.stringify(recordsets.recordset); //将查询结果转换成json格式
					//res.send(str);  //响应请求,将数据发送到前端
					console.log('执行sql脚本成功');  //在调试窗口显示
				}
			})
		};
		
		mssql.end;  //结束连接数据库
	});
})

module.exports = router;  //暴露模块,其它地方才能调用此模块

注意:要在程序入口加入下图方框中的代码,不然解析不了前端POST过来的数据
在这里插入图片描述

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐