1. 程式人生 > >一名Android開發者的微信小程式填坑之路(2)

一名Android開發者的微信小程式填坑之路(2)

前言

上一篇是九月二十七日寫的,而這一篇我動筆的時間是十月十日(特殊的日子),中間相隔十三天——當然是因為國慶節。說老實話,這十三天裡面我都沒有碰和小程式有關的東西——畢竟學習小程式的開發也只是起於興趣,而平時的工作並不會涉及與其相關的東西——但是在這十三天裡,我能明顯的感受到小程式熱正在逐漸的消退,或者說大家正在逐漸以一種較為平和的姿態接受它的存在,其實這是一件好事。期待公測的到來。

接下來我就直接進入正題了,另外,文末我想和大家分享一下我的國慶節。

PS:這篇文章是接著上一篇文章 寫的,建議沒看過上一篇文章的同學先看一下上一篇哈~

正文

6,後臺接收 post 請求要表單?

首先問題是:我要向後臺 post 一些資料,但是後臺需要接收一個表單,我應該怎樣獲得一個表單或者將本地的資料轉換成一個表單呢?

在寫 的提交乾貨模組的時候,我就遇到了這個問題。一開始我挺納悶的,明明是把後臺需要的資料都給傳過去了,結果後臺老是跟我說我的資料不對,後來我才發現是因為後臺那邊要求接收一個表單,而我傳過去的是一個 json 資料。於是我就開始了漫長的探索之旅。(就為了這一個問題,從晚上十一點多一直搞到第二天凌晨四點多。。。如果不是有一個群裡有個老司機幫忙說不定就死在這個問題上了)

首先我想的是能不能把現成的 json 資料直接轉化為 form 表單?因為我已經完成了獲取要輸的資訊然後把它變成了 json 資料的工作,如果能直接把 json 物件轉化為 form 物件的話我需要對程式做的改動肯定是最小的。然而遺憾的是,似乎並沒有可行的方案。

(也有可能是因為我 js 功底太差吧,我確實是沒有找到相應的方法,要生成一個 form 似乎是需要 document 的,而小程式中我們並不能夠得到它)

此路不通,另覓他途。在查閱資料的過程中,我發現在 HTML 中似乎是有 這個標籤的,然後我就興沖沖的又去翻閱了一下小程式的官方文件,果不其然,小程式還是很良心的,有這方面的描述:

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() 了看 給我返回的資料,它竟然還是個 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-Typeapplication/x-www-form-urlencoded ,不然還是會出問題。

通過上面的方式就可以愉快的給後臺傳表單啦~~~另外關於 這個標籤,雖然說他不會直接給我們返回 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,要實現多層列表?

在做 的每天干貨展示的頁面的時候,有一個這樣的頁面需要實現:

多層列表

這個東西說白了就是個兩層的列表,在原先做 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 資料裡面又裝了 tagsingleItems 等資料,其中 singleItems 又是一個數組,它裡面裝的也是一個一個的 json 資料,每個 json 資料裡裝了每個二級列表的 item 所需的資料。

具體的可以去我的專案程式碼裡去看,具體的程式碼路徑在這裡: 和 。

10,如何方便愉快的實現類似 Java 裡面的靜態變數的效果?

這點的話純粹是我的一點執念吧,我是從事 Android 開發的,也有點開發中的小癖好,喜歡把一些字串弄成全域性靜態的放到一個專門的地方去。如果是在 Java 裡面的話,我喜歡這樣做:

然後在呼叫的時候就可以這樣做:

String appId = Constants.AppSign.V_APP_ID;

這樣做我覺得很舒服,條理很清晰。但是在微信小程式中想要得到這樣的體驗就很困難——不過還是讓我找到了方法——在小程式裡面,是可以通過 module.exports 將一個 js 檔案模組化,然後讓別的 js 檔案通過 require( URL ) 引用的,我們可以通過這個特性來實現字串的全域性化,像這樣:

全域性化

這樣的話,我們就可以在需要使用的時候這樣:

使用

這個其實不算踩過的坑哈,只是一個 Android 程式設計師的小執念而已,大家可以無視。。。

結語

最近在惡補一些前端的東西,感覺我已經快成為一個前端開發工程師了。。。

PS:開始寫的時候是十月十日,但是中間停過一些時間,寫完已經不是了,(逃
PS:文中的所有的程式碼什麼的都可以在我的開源專案 中找到,歡迎大家去點 star 或是提 issue 哈。
PS:關於國慶,我想放一張圖:

國慶快樂

國慶快樂。