一名Android开发者的微信小程序填坑之路(2)
前言
上一篇是九月二十七日写的,而这一篇我动笔的时间是十月十日(特殊的日子),中间相隔十三天——当然是因为国庆节。说老实话,这十三天里面我都没有碰和小程序有关的东西——毕竟学习小程序的开发也只是起于兴趣,而平时的工作并不会涉及与其相关的东西——但是在这十三天里,我能明显的感受到小程序热正在逐渐的消退,或者说大家正在逐渐以一种较为平和的姿态接受它的存在,其实这是一件好事。期待公测的到来。
接下来我就直接进入正题了,另外,文末我想和大家分享一下我的国庆节。
PS:这篇文章是接着上一篇文章 一名Android开发者的微信小程序填坑之路(1) 写的,建议没看过上一篇文章的同学先看一下上一篇哈~
正文
6,后台接收 post 请求要表单?
首先问题是:我要向后台 post 一些数据,但是后台需要接收一个表单,我应该怎样获得一个表单或者将本地的数据转换成一个表单呢?
在写 wechat-weapp-gank 的提交干货模块的时候,我就遇到了这个问题。一开始我挺纳闷的,明明是把后台需要的数据都给传过去了,结果后台老是跟我说我的数据不对,后来我才发现是因为后台那边要求接收一个表单,而我传过去的是一个 json 数据。于是我就开始了漫长的探索之旅。(就为了这一个问题,从晚上十一点多一直搞到第二天凌晨四点多。。。如果不是有一个群里有个老司机帮忙说不定就死在这个问题上了)
首先我想的是能不能把现成的 json 数据直接转化为 form 表单?因为我已经完成了获取要输的信息然后把它变成了 json 数据的工作,如果能直接把 json 对象转化为 form 对象的话我需要对程序做的改动肯定是最小的。然而遗憾的是,似乎并没有可行的方案。(也有可能是因为我 js 功底太差吧,我确实是没有找到相应的方法,要生成一个 form 似乎是需要 document 的,而小程序中我们并不能够得到它)
此路不通,另觅他途。在查阅资料的过程中,我发现在 HTML 中似乎是有 <form> 这个标签的,然后我就兴冲冲的又去翻阅了一下小程序的官方文档,果不其然,小程序还是很良心的,有这方面的描述:
form然后我就兴冲冲的去按照官方的介绍用 <form> 标签来提交数据,js 里的代码是这样的:
formSubmit: function (event) {
wx.request({
url: Constant.BASE_URL + "/add2gank",
method: "POST",
//按照官方文档,event.detail.value应该就是 <form> 标签获得的数据
data: event.detail.value,
complete: function (res) {
//省略
}
});
}
我满心欢喜的以为可以了,结果并不可以。。。后台还是跟我说获得的数据有问题,结果我 console.log()
了看 <form> 给我返回的数据,它竟然还是个 json
。。。说好的 form
呢!感觉受到了欺骗。
濒临崩溃。幸好这时候一个老司机点醒了我:为啥那么纠结在本地数据是什么样子的?归根结底我们是要把数据传到后台去,那么只需要让数据在请求里面是 form 的格式不就 OK 了?所以 form 表单在请求里面是长什么样子的呢?
json数据:
{name: "lypeer", gender: "男"}
form数据:
"name=lypeer & gender=男"
所以只要直接对数据进行操作,不用去管什么鬼 json 对象 form 对象什么的,那位老司机写了个方法,我无耻的直接拿来用了:
function json2Form(json) {
var str = [];
for(var p in json){
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(json[p]));
}
return str.join("&");
}
ok,然后就可以用这个方法转换数据后来 post 一发:
formSubmit: function (event) {
console.log(event);
wx.request({
url: Constant.BASE_URL + "/add2gank",
header: {
"Content-Type": "application/x-www-form-urlencoded"
},
method: "POST",
data: Util.json2Form(event.detail.value).concat("&debug=false"),
complete: function (res) {
//省略
}
});
}
这里有一点需要注意,必需修改 content-Type
为 application/x-www-form-urlencoded
,不然还是会出问题。
通过上面的方式就可以愉快的给后台传表单啦~~~另外关于 <form> 这个标签,虽然说他不会直接给我们返回 form 表单,但是我感觉它还是很好用的,可以直接获得里面的很多信息,不用很麻烦的一个一个去获取数据了。不过这个标签也是有一些坑的,下面会讲到它。
7,解析 HTML 代码块?
有时候我们会有解析 HTML 代码块的需求(爬了一个网页需要解析,或者后台出于某种原因返回给你了一个 HTML 代码块),但是我们能获得的通常是一个 String 值( json 里返回的),在这种情况下通常我们会想到两种解析方式:直接使用正则匹配字符串或者将其装化成一个 DOM(Document Object Model,文档对象模型,没怎么接触过 JS 的同学可能对这个不太清楚) 然后解析。
直接使用正则的方式这里我就不具体说了,这玩意儿在有些时候还是很好用的,但是在有些时候不那么方便,毕竟它不是为了解析 HTML 而生的。而一提到转化为 DOM , 大家的脑海里就会浮现出这行代码来:
var el = document.createElement( 'html' );
el.innerHTML = htmlString;//htmlString是一串 HTML 代码的 String 值
再然后就可以对 el
执行一系列的解析操作了:
el.getElementById( idName );
el.getElementsByTagName( tagName );
......
毫无疑问,这种方式在大多数情况下是比正则来的简单方便的,毕竟你不需要绞尽脑汁去写合适的正则表达式了。那么问题来了,在小程序里面我们无法直接获得 window 和 document 对象,那么如何把一段 HTML 代码的 String 值转化为 DOM 呢?不知道那些前端老司机是怎么做的,反正我是这么做的:
function parseHtml(htmlBlock) {
var parser = new DOMParser();
return parser.parseFromString(htmlBlock, "text/html");
}
我惊讶的发现,虽然微信小程序里面没有 ducument , window 的概念,但是可以通过 DOMParser 对象来获得一个 document 对象 ......不要问我怎么发现的,这里面的艰辛不足为外人道也。
然后我们就可以愉快的通过这个返回的对象来进行一系列解析操作啦~~~
8,<form/>
里面无法获取 <picker/>
的取值?
在微信小程序的官方文档里,是指明了 <form/>
标签里可以提交 <picker/>
的数据的,但是如果你真的在 <form/>
标签里放了一个 <picker/>
的话,你会发现,童话里都是骗人的。什么鬼!说好的数据呢!!!死活都获取不了数据,甚至还会让整个程序崩掉。并且坑爹的是,在小程序官网上面的那个 DEMO 里面,关于 <form/>
标签的使用有一个例子,例子里面几乎包含了 <form/>
标签中会提取数据的所有控件,就是没有 <picker/>
。
那怎么办?这当然是难不倒我的。最终我采取了这样的方式来解决这个问题:
<picker bindchange="onPickerChanged" value="{{index}}" range="{{array}}">
<input class="picker" disabled="disabled" name="type" value="{{array[index]}}"/>
</picker>
这是一个 <form/>
标签里面的 <picker/>
标签,我采取的方式是用一个 <input/>
标签来获取 <picker/>
的值,然后让 <form/>
获取 <input/>
的值,从而达到将 <picker/>
里面的值传递给 <form/>
的目的。
9,要实现多层列表?
在做 wechat-weapp-gank 的每天干货展示的页面的时候,有一个这样的页面需要实现:
多层列表这个东西说白了就是个两层的列表,在原先做 Android 的时候这个是很容易的,直接嵌套嘛,但是现在做小程序的这个效果还是遇到了一些问题。这其中最大的问题就是在嵌套的过程中究竟在绑定数据的时候应该怎么写——第二个列表应该怎么传数据进去呢?第二个列表的列表项应该怎么获取数据呢?最后我摸索出来的结果是这样的:
<view class="frame" wx:for="{{data}}">
<view class="tag">{{item.tag}}</view>
<view wx:for="{{item.singleItems}}">
<view class="singleItem" href="{{item.src}}">{{index}},{{item.title}}</view>
</view>
</view>
其中 data
是一个数组,它里面装的是一个一个的的 json 数据,每个 json 数据里面又装了 tag
,singleItems
等数据,其中 singleItems
又是一个数组,它里面装的也是一个一个的 json 数据,每个 json 数据里装了每个二级列表的 item 所需的数据。
具体的可以去我的项目代码里去看,具体的代码路径在这里:post.wxml 和 post.js。
10,如何方便愉快的实现类似 Java 里面的静态变量的效果?
这点的话纯粹是我的一点执念吧,我是从事 Android 开发的,也有点开发中的小癖好,喜欢把一些字符串弄成全局静态的放到一个专门的地方去。如果是在 Java 里面的话,我喜欢这样做:
然后在调用的时候就可以这样做:
String appId = Constants.AppSign.V_APP_ID;
这样做我觉得很舒服,条理很清晰。但是在微信小程序中想要得到这样的体验就很困难——不过还是让我找到了方法——在小程序里面,是可以通过 module.exports
将一个 js 文件模块化,然后让别的 js 文件通过 require( URL )
引用的,我们可以通过这个特性来实现字符串的全局化,像这样:
这样的话,我们就可以在需要使用的时候这样:
使用这个其实不算踩过的坑哈,只是一个 Android 程序员的小执念而已,大家可以无视。。。
结语
最近在恶补一些前端的东西,感觉我已经快成为一个前端开发工程师了。。。
PS:文中的所有的代码什么的都可以在我的开源项目 wechat-weapp-gank 中找到,欢迎大家去点 star 或是提 issue 哈。
PS:关于国庆,我想放一张图:
国庆快乐国庆快乐。