在做微信公众号或者企业微信开发业务应用的时候,我们常常会涉及到图片预览、上传等的处理,往往业务需求不止一张图片,因此相对来说,需要考虑的全面一些,用户还需要对图片进行预览和相应的处理,在开始的时候我使用JSSDK方式,使用微信的SDK接口进行图片的上传、预览操作,后来发现通过URL.createObjectURL选定本地图片预览、上传也是非常方便的,本篇随笔针对同一个多图片的业务需求,使用JSSDK和URL.createObjectURL两种方式进行图片预览、上传、删除等常规的处理。

1、使用JSSDK对图片的处理

在一个公众号页面-问诊界面里面,我们需要让用户上传相关的图片,包括症状图片、处方图片等,每个列表可以上传多张图片,如下界面所示。

这里使用了SDK进行图片的上传处理,参考Weui的上传样式,选择本地几张图片,可以看到缩略图展示在图框里面,但是图片还没有上传,我们在保存问诊信息的时候,才启动图片文件的上传处理。

如果图片是在编辑界面中,我们需要考虑对现有图片进行删除的处理,删除前确认即可。

单击删除图标的按钮,提示用户进行图片删除确认即可。

以上就是我们几个图片处理的场景,我们来看看如何实现的。

我们以症状图片为例,它的界面HTML部分的代码如下所示。

<div class="weui-cells__title">症状图片</div>
<div class="weui-cells weui-cells_form">
<div class="weui-cell">
<div class="weui-cell__bd">
<div class="weui-uploader">
<!--编辑的时候,放置已有图片进行预览-->
<ul class="weui-weui-uploader__files" style="list-style-type: none" id="imgSickPreview"></ul>
<div class="weui-uploader__bd">
<!--放置选择的图片进行预览-->
<ul class="weui-weui-uploader__files" style="list-style-type: none" id="imgSick"></ul>
<div class="weui-uploader__input-box">
<!--图片上传的图标处理-->
<span id="uploaderSick" class="weui-uploader__input"></span>
</div>
</div>
</div>
</div>
</div>
</div>

为了使用微信JSSDK来实现上传、预览图片的功能,我们需要定义好对应的JS接口,如下代码所示。

    <script language="javascript">
var appid = '@ViewBag.appid';
var noncestr = '@ViewBag.noncestr';
var signature = '@ViewBag.signature';
var timestamp = '@ViewBag.timestamp'; wx.config({
debug: false,
appId: appid, // 必填,公众号的唯一标识
timestamp: timestamp, // 必填,生成签名的时间戳
nonceStr: noncestr, // 必填,生成签名的随机串
signature: signature, // 必填,签名,见附录1
jsApiList: [
'checkJsApi',
'chooseImage',
'previewImage',
'uploadImage',
'downloadImage',
'getLocalImgData'
]
}); ...... </script>

在上传图片之前,我们需要通过JSSDK的方式选择图片,这里用到了chooseImage的接口,大概所需的代码如下所示。

        //上传图片集合[用微信上传的时候,记录微信mediaId集合]
var images = {
localSickId: [],//病情
localPresId: [],//处方 serverSickId: [],
serverPresId: []
}; //图片选择
$("#uploaderSick").click(function () {
chooseImage("imgSick", "sick");
});
$("#uploaderPres").click(function () {
chooseImage("imgPres", "pres");
}); //选择图片显示
function chooseImage(ctrlName, type) {
//清空集合
if (type == "sick") {
images.localSickId = [];
} else {
images.localPresId = [];
} wx.chooseImage({
count: 3, // 默认9
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: function (res) {
var ctrl = $("#" + ctrlName);
ctrl.html("");//清空图片显示 //localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
if (type == "sick") {
images.localSickId = res.localIds;
} else {
images.localPresId = res.localIds;
} //动态增加img标识
$.each(res.localIds, function (index, item) {
ctrl.append("<img class='weui-uploader__file' src='" + item + "' />");
});
}
});
}

选择图片后,就是将图片的缩略图动态的增加在指定图片框里面。然后在保存数据的时候,使用JSSDK提交图片到微信服务器,我们服务器后台再从微信服务器获取图片(通过媒体id)。

这里我们定义了两类的图片,方便区分,分别是症状图片和处方图片,因此需要定义两个类别的变量,分别存储本地和服务器返回的id集合。

我们在进行表单提交的时候,需要确认一些必填项,然后在检查是否有文件需要上传,如果有则执行上传处理后提交表单,大概的处理代码如下所示。

        //上传数据
$("#btnOK").click(function () {
var PatientName = $("#PatientName").val();
if (PatientName == '' || PatientName == undefined) {
$.toast('患者姓名不能为空', "forbidden");
return;
}
var ProblemDetail = $("#ProblemDetail").val();
if (ProblemDetail == '' || ProblemDetail == undefined) {
$.toast('详细描述不能为空', "forbidden");
return;
} //上传图片
if (images.localSickId.length > 0 || images.localPresId.length > 0) {
uploadImage(submitCallback);//通过就提交数据
} else {
submitCallback();
}
});

这里主要的图片上传处理,就是 uploadImage 函数的处理了,而submitCallback这是定义一个函数上传表单数据的。

由于微信JSSDK上传图片,是一个个上传的,我们需要把它们串联起来,一并上传。uploadImage 里面定义了一个内部函数,依次进行图片的上传。

我们通过序号来标识两类图片,图片上传成功后,我们把图片媒体的id(JSSDK返回的)记录下来,统一提交给对应数据库记录,在后台进行图片文件的提取即可。

        //上传图片
function uploadImage(callback) {
var localIds = images.localSickId.concat(images.localPresId);//合并数组
var i = 0, length = localIds.length;
//$.toast(length); images.serverSickId = [];
images.serverPresId = []; //定义一个子级函数,方便递归调用
function upload(callback) {
wx.uploadImage({
localId: localIds[i],
success: function (res) {
i++; //成功后加入不同的集合
if (i <= images.localSickId.length) {
images.serverSickId.push(res.serverId);//第一部分
} else {
images.serverPresId.push(res.serverId);//第二部分
} if (i < length) {
upload(callback);
}else if (callback != undefined) {
callback();//回调函数
}
},
fail: function (res) {
alert(JSON.stringify(res));
}
});
}; upload(callback);
}

其中我们的定义的callback函数,是用来最后上传完成后,执行表单的记录存储的,表单包含各种输入和图片的ID信息,如下是详细的表单保存操作代码。

        //在上传图片后触发的回调函数
function submitCallback() {
var druglist = [];//构造集合对象
for (var key in itemDict) {
//Drug_ID,DrugName,How,Freq
druglist.push({
'Drug_ID': key, "DrugName": itemDict[key], 'How': howDict[key],
'Freq': freqDict[key], 'Quantity': quantityDict[key]
});
}
var url = "/H5/DrugInquirySave?openid=@ViewBag.openid";
var postData = {
PatientName: $("#PatientName").val(),
Gender: $("#Gender").val(),
BirthDate: $("#BirthDate").val(),
Telephone: $("#Telephone").val(),
ProblemDetail: $("#ProblemDetail").val(),
Creator: $("#Creator").val(),
ProblemItems: $("input[name='ProblemItems']:checked").val(),
@if (ViewBag.Info != null) {
<text>
ID: '@ViewBag.Info.ID',
</text>
} SickAttachGUID: $("#SickAttachGUID").val(),
PresAttachGUID: $("#PresAttachGUID").val(),
ServerSickId: JSON.stringify(images.serverSickId),
ServerPresId: JSON.stringify(images.serverPresId),
DrugList: JSON.stringify(druglist)
}; $.post(url, postData, function (json) {
//转义JSON为对象
var data = $.parseJSON(json);
if (data.Success) {
$.toast("处方已提交审核中,稍后请到处方查询查看。");
//WeixinJSBridge.call('closeWindow');//关闭窗口
location.href = "/h5/Prescription";//跳转到处方页面
}
else {
$.toast("保存失败:" + data.ErrorMessage, "forbidden");
}
});
};

我们注意到,我们服务端返回的ID集合,我们分别放在了两个字段里面提交到后台处理。

    ServerSickId: JSON.stringify(images.serverSickId),
ServerPresId: JSON.stringify(images.serverPresId),

在后台,我们首先需要提取用户提交的基础表单数据,如下是后台定义的函数处理

这些是常规的表单信息,我们提交到微信服务器的图片信息也需要提取出来的,这些图片分两类,每类都包含多个字符串组成的图片ID集合。

后台主要就是根据这些ID,使用微信基础接口,获取临时图片的接口方式,把图片从服务器上下载下来存储到本地服务器上。

其中UploadFile函数就是封装了如何实现图片获取、图片存储的处理逻辑,主要的代码部分逻辑如下所示。

这种方式很好的利用了JSSDK的图片选择、上传的处理,实现了我们所需要的图片预览、选择、上传等一系列操作,也能够满足实际的功能需要。

不过总感觉把图片绕了一圈再回来不太好而已。

2、使用URL.createObjectURL对图片的处理

前面介绍了使用微信JSSDK方式实现图片预览、选择、上传等一系列操作,在上传文件的时候,感觉绕了一圈再回来,一直希望能够直接把文件直接提交到服务器上更好,就像我们一般的Web应用上传附件一样感觉更好一些,后来发现了可以通过URL.createObjectURL进行相关的处理,参考了一些案例,对前面介绍的JSSDK的图片上传方式进行改良,从而实现了把图片附件通过表单的方式直接提交到自己后台服务器上了,下面开始介绍一下这种方式的思路和实现代码。

首先我们定义一个预览图片的列表和一个Input的文件控件元素,替代前面的做法,如下所示。

<div class="weui-cells__title">症状图片</div>
<div class="weui-cells weui-cells_form">
<div class="weui-cell">
<div class="weui-cell__bd weui-cell_primary">
<div class="weui-uploader">
<!--预览图片的列表-->
<ul class="weui-uploader__files" id="imgSick">
</ul>
<div class="weui-uploader__input-box">
<!--上传图片附件控件-->
<input id="uploaderSick" class="weui-uploader__input" type="file" accept="image/*" multiple="">
</div>
</div>
</div>
</div>
</div>

为了实现选择图片文件的时候,预览图片的列表可以动态变化(动态增加 li 项目),我们需要定义对应的事件来实现这个操作。

        //存放文件图片的集合
var fileSick = new Array();
var filePres = new Array();
function initImage() {
var tmpl = '<li class="weui-uploader__file" style="background-image:url(#url#)"></li>',
$gallery = $("#gallery"),
$galleryImg = $("#galleryImg"), $uploaderSick = $("#uploaderSick"),
$imgSick = $("#imgSick"),
$uploaderPres = $("#uploaderPres"),
$imgPres = $("#imgPres"); //症状图片上传
$uploaderSick.on("change", function (e) {
var src, url = window.URL || window.webkitURL || window.mozURL,
files = e.target.files; for (var i = 0, len = files.length; i < len; ++i) {
var file = files[i];
fileSick.push(file);//加入集合 if (url) {
src = url.createObjectURL(file);
} else {
src = e.target.result;
}
$imgSick.append($(tmpl.replace('#url#', src)));
}
}); ..............

我们注意到了,这里没有使用chooseImage的JSSDK接口,而是通过 url.createObjectURL(file) 的方式获取路径,展示在图片列表控件里面。

对于动态增加的图片,我们可以让它支持单击预览的方式,预览其实是把图片放在一个预览层里面。

    var index; //第几张图片
var category;//那个类别
var imgid;//图片ID
//症状图片单击处理
$imgSick.on("click", "li", function() {
index = $(this).index();
category = "sick";
imgid = $(this).attr("id");
$galleryImg.attr("style", this.getAttribute("style"));
$gallery.fadeIn(100);
});

预览层的DIV是放在主界面上的,主界面是一个放置图片的区域,底部是一个删除按钮,用来我们实现图片删除操作的。

<!--图片预览层-->
<div class="weui-gallery" id="gallery">
<span class="weui-gallery__img" id="galleryImg" style="width:auto"></span>
<div class="weui-gallery__opr">
<a href="javascript:" class="weui-gallery__del">
<i class="weui-icon-delete weui-icon_gallery-delete"></i>
</a>
</div>
</div>

预览层再次单击的时候关闭,执行的JS代码如下所示。

$gallery.on("click", function() {
$gallery.fadeOut(100);
});

删除图片的时候,我们区分是存在服务器的图片,还是本地临时选择的图片,区别对待。如果服务器图片,需要提示确认删除,如果是本地临时图片,直接移除即可。

//删除图片(根据类别和序号处理)
$(".weui-gallery__del").click(function () {
console.log(index + ',' + category + ',' + imgid);//记录显示 //如果是在服务端的图片,确认后移除
if (imgid != undefined && imgid != '') {
$.confirm("您确定要永久删除该图片吗?", "永久删除?", function () {
var url = "/H5/DeleteAttachment?openid=@ViewBag.openid";
var postData = {
id: imgid.replace(/img_/, '') //控件id去掉前缀为真正附件ID
}; $.post(url, postData, function (json) {
//转义JSON为对象
var data = $.parseJSON(json);
if (data.Success) {
$.toptip("删除成功!", 'success'); //在界面上找到对应控件ID,移除控件
RemoveImg();
}
else {
$.toast("操作失败:" + data.ErrorMessage, "forbidden");
}
});
});
} else {
RemoveImg(); //普通图片快速移除
};
});

其中移除图片显示的JS代码如下所示。

//移除对应类别的图片
function RemoveImg() {
if (category == "sick") {
$imgSick.find("li").eq(index).remove();
fileSick.splice(index, 1);
} else {
$imgPres.find("li").eq(index).remove();
filePres.splice(index, 1);
}
};

我们要使用表单上传文件的方式,就需要在JS里面创建一个FormData的对象,用来承载文件内容,如下所示

var formData = new FormData();//构建一个FormData存储复杂对象

如果是常规的表单数据,我们通过键值,把内容填入FormData即可,如下所示。

var formData = new FormData();//构建一个FormData存储复杂对象
formData.append("PatientName", $("#PatientName").val());

如果是图片附件的,我们则需要遍历集合文件,把它们逐一加入对应键值里面,为了区分不同的类别文件,我们使用不同的前缀方式,如下代码所示。

//加入症状图片
for (var i = 0; i < fileSick.length; i++){
formData.append("sick_" + i, fileSick[i]);
};
//加入处方图片
for (var i = 0; i < filePres.length; i++){
formData.append("pres_" + i, filePres[i]);
};
//提交表单数据和文件
var url = "/H5/DrugInquirySave2?openid=@ViewBag.openid";
$.ajax({
url: url,
type: 'post',
processData: false,
contentType: false,
data: formData,
success: function (json) {
//转义JSON为对象
var data = $.parseJSON(json);
if (data.Success) {
$.toast("处方已提交审核中,稍后请到处方查询查看。");
//WeixinJSBridge.call('closeWindow');//关闭窗口
location.href = "/h5/Prescription";//跳转到处方页面
}
else {
$.toast("保存失败:" + data.ErrorMessage, "forbidden");
}
}
});

在后台的处理函数 DrugInquirySave2 里面,我们需要把文件按键名提取出来,根据文件键名的不同,放到不同给的集合里面存储起来即可。

如下是DrugInquirySave2 函数里面的部分代码,用来处理收到的表单文件集合。然后我们在把文件写入文件系统即可,这样省却了对JSSDK提交文件,再去微信服务器提取文件方式的麻烦,直接由客户端把文件上传的自己的文件服务器了。

#region 通过文件附件方式获取
var files = Request.Files;
if (files != null && files.Count > )
{
LogTextHelper.Info(string.Format("收到文件:{0}", files.Count));//测试 foreach (string key in files.Keys)
{
LogTextHelper.Info(string.Format("收到文件key:{0}", key)); var fileData = files[key];
bool isSickImage = key.ToLower().IndexOf("sick") >= ;//判断是否为问诊图片分类
if (fileData != null)
{
HttpContext.Request.ContentEncoding = Encoding.GetEncoding("UTF-8");
HttpContext.Response.ContentEncoding = Encoding.GetEncoding("UTF-8");
HttpContext.Response.Charset = "UTF-8"; string fileName = Path.GetFileName(fileData.FileName); //原始文件名称
string fileExtension = Path.GetExtension(fileName); //文件扩展名 FileUploadInfo fileInfo = new FileUploadInfo();
fileInfo.FileData = ReadFileBytes(fileData);
if (fileInfo.FileData != null)
{
fileInfo.FileSize = fileInfo.FileData.Length;
}
//判断图片类别分组
fileInfo.Category = isSickImage ? "问诊图片" : "处方图片";
fileInfo.FileName = fileName;
fileInfo.FileExtend = fileExtension;
//判断属于那个分组【这里只有两个分组】
fileInfo.AttachmentGUID = isSickImage ? SickAttachGUID : PresAttachGUID; fileInfo.AddTime = DateTime.Now;//创建时间
fileInfo.Editor = openid;//记录人
fileInfo.Owner_ID = info.ID;//属于主表记录 result = BLLFactory<FileUpload>.Instance.Upload(fileInfo);
if (!result.Success)
{
LogTextHelper.Error("上传文件失败:" + result.ErrorMessage);
}
}
}
}
#endregion

编辑现有记录的时候,也可以实现对已有图片的删除操作,临时文件的预览处理和再次上传等操作。

3、两种图片处理方式的总结

本篇随笔是基于公众号上传图片文件的两种方式的处理,分别是使用微信JSSDK和使用URL.createObjectURL上传预览图片的不同处理对比,两种方式都能够满足图片的处理操作。对比处理代码,可能使用后者可能更加简洁一些。而且微信浏览器对URL.createObjectURL的支持也非常不错,可以在微信开发工具和实际环境上都正常使用。

微信开发中使用微信JSSDK和使用URL.createObjectURL上传预览图片的不同处理对比的更多相关文章

  1. Vue 中使用 viewerjs进行本地上传预览图片

    https://www.cnblogs.com/shenjp/p/9754171.html 如果图片路径是 接口的返回信息的话,将路径存储在数组中,在this.$nextTick中实例化Viewer: ...

  2. [转载红鱼儿]Delphi实现微信开发(3)如何使用multipart/form-data格式上传文件

    开始前,先看下要实现的微信接口,上传多媒体文件,这个接口是用Form表单形式上传的文件.对我来说,对http的Form表单一知半解,还好,查到这个资料,如果你也和我一样,必须看看这篇文章. 在xali ...

  3. HTML5开发笔记:图片上传预览

    我们知道通过<input type="file">可以用来进行一个图片或者文件的上传,然而浏览器自带的一个缩略图预览的功能其实是相当不美观的,很多时候我们希望可以在上传 ...

  4. Ext中图片上传预览的问题,困扰了好几天终于解决了,记录下

    { columnWidth:.50, xtype:'textfield', style:"padding-top:5px", name:'goodsMainPhoto', id:' ...

  5. 关于html中图片上传预览的实现

    本地图片预览 第一种方法 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type& ...

  6. html中图片上传预览的实现

    本地图片预览 第一种方法 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type& ...

  7. 有关微信开发中errorcode:-1 errmsg:system error 错误的一点原因

    如果你在微信开发中遇到{"errcode":-1,"errmsg":"system error,hints:[req_id:]"}这样的错误 ...

  8. 微信开发中使用curl忽略https证书

    http://blog.csdn.net/ljh504429906/article/details/51103519 微信开发中需要使用http及https的post与get请求实现api的调用.   ...

  9. Java开发微信公众号(五)---微信开发中如何获取access_token以及缓存access_token

    获取access_token是微信api最重要的一个部分,因为调用其他api很多都需要用到access_token.比如自定义菜单接口.客服接口.获取用户信息接口.用户分组接口.群发接口等在请求的时候 ...

随机推荐

  1. docker容器内 java应用程序启动慢

    原谅我对JVM 不是很熟悉. 参考http://hongjiang.info/tomcat-startup-slowly-in-docker/ 感谢作者.

  2. Vue 前端uni-app多环境配置部署服务器的问题

    目录 前端Vue 针对问题 package.json描述 多环境部署 查看源码获取解决方案 转载请标明出处: http://dujinyang.blog.csdn.net/ 本文出自:[奥特曼超人的博 ...

  3. Redis小白入门系列

    一.从NoSQL说起 NoSQL 是 Not only SQL 的缩写,大意为"不只是SQL",说明这项技术是传统关系型数据库的补充而非替代.在整个NoSQL技术栈中 MemCac ...

  4. 一、springboot起航

    # 前言 之前零零散散的学习了一些springboot的知识,以及搭建一些springboot的项目,甚至还有一些项目应用到实际项目中了,但是突然有一天想要建一个自己的项目网站.发现自己不知道从何开始 ...

  5. spring字符编码filter

    项目中的字符编码问题,spring提供统一的字符处理filter,只需要在项目入口web.xml中配置CharacterEncodingFilter即可,具体配置如下: <!-- 配置过滤器,同 ...

  6. 从零开始入门 K8s | 应用编排与管理(酒祝)

    一.需求来源 背景问题 首先来看一下背景问题.如下图所示:如果我们直接管理集群中所有的 Pod,应用 A.B.C 的 Pod,其实是散乱地分布在集群中. 现在有以下的问题: 首先,如何保证集群内可用 ...

  7. mysql创建表时字段类型选择与优化

    一.选择原则 1.应该尽量使用可以正确存储数据的最小字段类型 2.选用简单的数据类型,例如:一个是尽量用mysql内置的字段类型来存储日期和时间:另一个存储IP地址尽量用整型:能用整型的尽量不用字符串 ...

  8. mysql备份脚本并保留7天

    脚本需求: 每天备份mysql数据库,保留7天的脚本. 存放在/opt/dbbak目录中. 脚本名称为database_xxxx-xx-xx.sql 脚本内容: #!/bin/bash export ...

  9. 阿里云服务器CentOS6.9 tomcat配置域名访问

    之前一直是ip访问项目,今天申请到一个测试域名,想要用设置用域名访问项目. 1.进入阿里云服务器中,修改tomcat中server.xml文件 cd /usr/local/apache-tomcat/ ...

  10. How to setup Electrum testnet mode and get BTC test coins

    For some reason we need to use BTC test coins, but how to set up the Bitcoin testnet wallet and get ...