上一篇是九月二十七日寫(xie) 的,而這一篇我動筆的時間是十月十日(特殊的日子),中間相隔十三天——當然是因為(wei) 國慶節。說老實話,這十三天裏麵我都沒有碰和小程序有關(guan) 的東(dong) 西——畢竟學習(xi) 小程序的開發也隻是起於(yu) 興(xing) 趣,而平時的工作並不會(hui) 涉及與(yu) 其相關(guan) 的東(dong) 西——但是在這十三天裏,我能明顯的感受到小程序熱正在逐漸的消退,或者說大家正在逐漸以一種較為(wei) 平和的姿態接受它的存在,其實這是一件好事。期待公測的到來。
接下來我就直接進入正題了,另外,文末我想和大家分享一下我的國慶節。
PS:這篇文章是接著上一篇文章 一名androids開發者的微信小程序填坑之路《上》 寫(xie) 的,建議沒看過上一篇文章的同學先看一下上一篇哈~
首先問題是:我要向後台 post 一些數據,但是後台需要接收一個(ge) 表單,我應該怎樣獲得一個(ge) 表單或者將本地的數據轉換成一個(ge) 表單呢?
在寫(xie) wechat-weapp-gank 的提交幹貨模塊的時候,我就遇到了這個(ge) 問題。一開始我挺納悶的,明明是把後台需要的數據都給傳(chuan) 過去了,結果後台老是跟我說我的數據不對,後來我才發現是因為(wei) 後台那邊要求接收一個(ge) 表單,而我傳(chuan) 過去的是一個(ge) json 數據。於(yu) 是我就開始了漫長的探索之旅。(就為(wei) 了這一個(ge) 問題,從(cong) 晚上十一點多一直搞到第二天淩晨四點多。。。如果不是有一個(ge) 群裏有個(ge) 老司機幫忙說不定就死在這個(ge) 問題上了)
首先我想的是能不能把現成的 json 數據直接轉化為(wei) form 表單?因為(wei) 我已經完成了獲取要輸的信息然後把它變成了 json 數據的工作,如果能直接把 json 對象轉化為(wei) form 對象的話我需要對程序做的改動肯定是最小的。然而遺憾的是,似乎並沒有可行的方案。(也有可能是因為(wei) 我 js 功底太差吧,我確實是沒有找到相應的方法,要生成一個(ge) form 似乎是需要 document 的,而小程序中我們(men) 並不能夠得到它)
此路不通,另覓他途。在查閱資料的過程中,我發現在 HTML 中似乎是有 這個(ge) 標簽的,然後我就興(xing) 衝(chong) 衝(chong) 的又去翻閱了一下小程序的官方文檔,果不其然,小程序還是很良心的,有這方麵的描述:
然後我就興(xing) 衝(chong) 衝(chong) 的去按照官方的介紹用 標簽來提交數據,js 裏的代碼是這樣的:
formSubmit: function (event) {
wx.request({
url: Constant.BASE_URL + "/add2gank",
method: "POST",
//按照官方文檔,event.detail.value應該就是
我滿心歡喜的以為(wei) 可以了,結果並不可以。。。後台還是跟我說獲得的數據有問題,結果我 console.log()
了看 給我返回的數據,它竟然還是個(ge) json
。。。說好的 form
呢!感覺受到了欺騙。
瀕臨(lin) 崩潰。幸好這時候一個(ge) 老司機點醒了我:為(wei) 啥那麽(me) 糾結在本地數據是什麽(me) 樣子的?歸根結底我們(men) 是要把數據傳(chuan) 到後台去,那麽(me) 隻需要讓數據在請求裏麵是 form 的格式不就 OK 了?所以 form 表單在請求裏麵是長什麽(me) 樣子的呢?
json數據:
{name: "lypeer", gender: "男"}
form數據:
"name=lypeer & gender=男"
所以隻要直接對數據進行操作,不用去管什麽(me) 鬼 json 對象 form 對象什麽(me) 的,那位老司機寫(xie) 了個(ge) 方法,我無恥的直接拿來用了:
function json2Form(json) {
var str = [];
for(var p in json){
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(json[p]));
}
return str.join("&");
}
ok,然後就可以用這個(ge) 方法轉換數據後來 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
為(wei) application/x-www-form-urlencoded
,不然還是會(hui) 出問題。
通過上麵的方式就可以愉快的給後台傳(chuan) 表單啦~~~另外關(guan) 於(yu) 這個(ge) 標簽,雖然說他不會(hui) 直接給我們(men) 返回 form 表單,但是我感覺它還是很好用的,可以直接獲得裏麵的很多信息,不用很麻煩的一個(ge) 一個(ge) 去獲取數據了。不過這個(ge) 標簽也是有一些坑的,下麵會(hui) 講到它。
有時候我們(men) 會(hui) 有解析 HTML 代碼塊的需求(爬了一個(ge) 網頁需要解析,或者後台出於(yu) 某種原因返回給你了一個(ge) HTML 代碼塊),但是我們(men) 能獲得的通常是一個(ge) String 值( json 裏返回的),在這種情況下通常我們(men) 會(hui) 想到兩(liang) 種解析方式:直接使用正則匹配字符串或者將其裝化成一個(ge) DOM(Document Object Model,文檔對象模型,沒怎麽(me) 接觸過 JS 的同學可能對這個(ge) 不太清楚) 然後解析。
直接使用正則的方式這裏我就不具體(ti) 說了,這玩意兒(er) 在有些時候還是很好用的,但是在有些時候不那麽(me) 方便,畢竟它不是為(wei) 了解析 HTML 而生的。而一提到轉化為(wei) DOM , 大家的腦海裏就會(hui) 浮現出這行代碼來:
var el = document.createElement( 'html' );
el.innerHTML = htmlString;//htmlString是一串 HTML 代碼的 String 值
再然後就可以對 el
執行一係列的解析操作了:
el.getElementById( idName );
el.getElementsByTagName( tagName );......
毫無疑問,這種方式在大多數情況下是比正則來的簡單方便的,畢竟你不需要絞盡腦汁去寫(xie) 合適的正則表達式了。那麽(me) 問題來了,在小程序裏麵我們(men) 無法直接獲得 window 和 document 對象,那麽(me) 如何把一段 HTML 代碼的 String 值轉化為(wei) DOM 呢?不知道那些前端老司機是怎麽(me) 做的,反正我是這麽(me) 做的:
function parseHtml(htmlBlock) {
var parser = new DOMParser();
return parser.parseFromString(htmlBlock, "text/html");}
我驚訝的發現,雖然微信小程序裏麵沒有 ducument , window 的概念,但是可以通過 DOMParser 對象來獲得一個(ge) document 對象 ……不要問我怎麽(me) 發現的,這裏麵的艱辛不足為(wei) 外人道也。
然後我們(men) 就可以愉快的通過這個(ge) 返回的對象來進行一係列解析操作啦~~~
<form/>
裏麵無法獲取 <picker/>
的取值?在微信小程序的官方文檔裏,是指明了 <form/>
標簽裏可以提交 <picker/>
的數據的,但是如果你真的在 <form/>
標簽裏放了一個(ge) <picker/>
的話,你會(hui) 發現,童話裏都是騙人的。什麽(me) 鬼!說好的數據呢!!!死活都獲取不了數據,甚至還會(hui) 讓整個(ge) 程序崩掉。並且坑爹的是,在小程序官網上麵的那個(ge) DEMO 裏麵,關(guan) 於(yu) <form/>
標簽的使用有一個(ge) 例子,例子裏麵幾乎包含了 <form/>
標簽中會(hui) 提取數據的所有控件,就是沒有 <picker/>
。
那怎麽(me) 辦?這當然是難不倒我的。最終我采取了這樣的方式來解決(jue) 這個(ge) 問題:
<picker bindchange="onPickerChanged" value="{{index}}" range="{{array}}">
<input class="picker" disabled="disabled" name="type" value="{{array[index]}}"/>
</picker>
這是一個(ge) <form/>
標簽裏麵的 <picker/>
標簽,我采取的方式是用一個(ge) <input/>
標簽來獲取 <picker/>
的值,然後讓 <form/>
獲取 <input/>
的值,從(cong) 而達到將 <picker/>
裏麵的值傳(chuan) 遞給 <form/>
的目的。
在做 wechat-weapp-gank 的每天幹貨展示的頁麵的時候,有一個(ge) 這樣的頁麵需要實現:
這個(ge) 東(dong) 西說白了就是個(ge) 兩(liang) 層的列表,在原先做 androids 的時候這個(ge) 是很容易的,直接嵌套嘛,但是現在做小程序的這個(ge) 效果還是遇到了一些問題。這其中最大的問題就是在嵌套的過程中究竟在綁定數據的時候應該怎麽(me) 寫(xie) ——第二個(ge) 列表應該怎麽(me) 傳(chuan) 數據進去呢?第二個(ge) 列表的列表項應該怎麽(me) 獲取數據呢?最後我摸索出來的結果是這樣的:
<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
是一個(ge) 數組,它裏麵裝的是一個(ge) 一個(ge) 的的 json 數據,每個(ge) json 數據裏麵又裝了 tag
,singleItems
等數據,其中 singleItems
又是一個(ge) 數組,它裏麵裝的也是一個(ge) 一個(ge) 的 json 數據,每個(ge) json 數據裏裝了每個(ge) 二級列表的 item 所需的數據。
具體(ti) 的可以去我的項目代碼裏去看,具體(ti) 的代碼路徑在這裏:post.wxml 和 post.js。
這點的話純粹是我的一點執念吧,我是從(cong) 事 androids 開發的,也有點開發中的小癖好,喜歡把一些字符串弄成全局靜態的放到一個(ge) 專(zhuan) 門的地方去。如果是在 Java 裏麵的話,我喜歡這樣做:
然後在調用的時候就可以這樣做:
String appId = Constants.AppSign.V_APP_ID;
這樣做我覺得很舒服,條理很清晰。但是在微信小程序中想要得到這樣的體(ti) 驗就很困難——不過還是讓我找到了方法——在小程序裏麵,是可以通過module.exports
將一個(ge) js 文件模塊化,然後讓別的 js 文件通過 require( URL )
引用的,我們(men) 可以通過這個(ge) 特性來實現字符串的全局化,像這樣:
這樣的話,我們(men) 就可以在需要使用的時候這樣:
這個(ge) 其實不算踩過的坑哈,隻是一個(ge) androids 程序員的小執念而已,大家可以無視。。。
最近在惡補一些前端的東(dong) 西,感覺我已經快成為(wei) 一個(ge) 前端開發工程師了。。。