「前端」weex頁面傳參

尚妝產品技術刊讀發表於2017-08-15

本文來自尚妝前端團隊南洋

發表於尚妝github部落格,歡迎訂閱!

前言

我司在weex上的應用是保證三端統一,為了延續web開發體驗,統一在三端的跳轉都採用url的形式,即採用\元件,或者自定義的openUrl方法進行跳轉。

假如現在點選B按鈕跳轉到/b.html頁面,在vue檔案中統一書寫openUrl('/b.html')。H5中就是簡單的呼叫window.location.href = /b.html,在native中會開啟一個檢視,然後去下載跟/b.html對應的b.min.jsjs檔案,進行原生檢視渲染。頁面與js檔案的對映關係以及如何維護可以翻閱之前的文章檢視App的跳轉規則的weex支援方案設計。

統一採用url跳轉的方式進行頁面跳轉,為了傳參方便,我們也統一採用在url後拼接引數的形式進行頁面間傳參。

正向傳參

不管是weex(native)還是weex(H5)都是通過頁面的url進行跳轉。

假設案例:

x.com/a.html跳轉到x.com/b.html?age=12

1)weex(native) > weex(native) 例項化時從url中取得引數並傳入到例項中

weex文件中寫到

每個 Weex 頁面都有被建立、被銷燬兩個必經階段,同時在 Weex 頁面執行過程中,native 有機會主動向 Weex 頁面傳送訊息。
Native 有機會在建立一個 Weex 頁面的時候,傳入一份外部資料,JS 框架也有機會藉此機會為相同的 JS bundle 配合不同的 data 生成不同的頁面內容。

由上可知native在渲染一個weex頁面的時候有機會往這個weex頁面傳入一個Object型別的資料,資料能通過weex.config取得。

在我司的設計中,native首先會擷取跳轉的url,然後擷取下引數,再把引數傳入到weex例項中去。這樣我們就能通過weex.config.age進行資料的獲取,從而渲染不同的頁面內容。

[_instance renderWithURL:[NSURL URLWithString:mstrURL] options:[self SHWeexOptionsWithH5URL:mstrH5URL withURL:mstrURL] data:nil];複製程式碼

2)weex(web)> weex(web)在weex-vue-render層面從url讀取引數,寫入weex.config

native實現這上述講到的方式進行資料傳遞,那麼web端也要以相同的方式weex.config.age這種方式去取得頁面中的引數age。

本司web端的weex依賴檔案是通過webpack打包的方式,所以在requireweex-vue-render依賴後,獲取當前url的引數,再存進weex.config物件就好了。

require('weex-vue-render')

// hack 將頁面url的引數寫入到weex.config中
// app已經有這樣的方法,h5自己實現
let urlParamObj = {};
try {
  urlParamObj = utils.parseUrl(window.location.search.slice(1), '&', "=", {maxKeys: 0});  
} catch (error) {
  console.log('--------------weex.js parseUrl---------------------');
  console.log(error);
  console.log('------------------------------------');
}


for (let key in urlParamObj) {
  window.weex.config[key] = encodeURIComponent(urlParamObj[key]);
}複製程式碼

3)native > weex(native) 同理
4)native > weex(web) 同理

對於3、4兩種情況,native跳轉weex,不管是跳到weex(native)還是跳轉到weex(web),都是使用url的形式進行跳轉。例:x.com/b.html?age=12。上面也講到了在weex頁面native和web如如何將引數寫入weex.config物件中去的。要取得引數,統一在vue中編寫weex.config.age便能取得傳遞進來的age引數。

至此我們統一了三端(ios、android、H5)從A頁面到B頁面正向的傳參方式。

反向傳參

1)weexA(native) > weexB(native),weexB頁面選擇完畢返回weexA頁面, weexB(native) > weexA(native)

在提交訂單頁面我們可以選擇優惠券,進入到優惠券使用頁面,首先會進行正向傳參,因為選擇優惠券頁面會使用提交訂單頁的訂單資料。

然後在選擇優惠券頁面選擇任意優惠券會回到提交訂單頁,這時需要攜帶優惠券資料回去,我們稱這個為反向傳參。

檢視官網我們本可以使用BroadcastChannel這個api去做例項間的資料傳遞,但是在vue的JS Framework中還不支援這個特性,所以我們暫時使用的是globalEvent這個例項級別的api去代替應用級別的資料傳遞。

我們首先在公司內部整合的module中增加了fireGlobalEvent方法,在選擇優惠券頁面呼叫這個方法。

fireGlobalEvent('getConpon', {
    id: '3323',
  }, function () {
  if (web) {

  } else {
    navigator.pop()
  }
})複製程式碼

這個方法首先註冊了getCoupon事件,然後傳遞了資料物件

{
    id: '3323'
}複製程式碼

最後註冊了一個回撥,當前頁面會執行這個回撥,回退上一頁。

而在上一頁(提交訂單頁),註冊了一個事件監聽,當這個事件名被觸發了,就接收來自這個事件的資料。

const globalEvent = weex.requireModule('globalEvent');
globalEvent.addEventListener('getCoupon', function (e) {
  console.log("get getCoupon")
});複製程式碼

這是業務邏輯中的實現,我們再來看看native為了達到返回上一頁並傳參效果做了什麼處理(android為例)。

public void fireGlobalEvent(String name, String data, final JSCallback callback) {
        SHStorageManager.putToCache(SHWeexConstants.WEEX, SHWeexConstants.NAME, name);
        SHStorageManager.putToCache(SHWeexConstants.WEEX, SHWeexConstants.DATA, data);

        if (null != callback) {
            callback.invoke(new JSONObject());
        }
    }複製程式碼

當在業務中呼叫fireGlobalEvent方法時,native會把傳入的事件名和data存入快取。然後執行業務中定義的回撥函式,而回撥中會有navigator.pop()方法,意味著退出當前weex例項進入到上一個頁面。

public void onResume() {
        if (wxInstance != null) {
            wxInstance.onActivityResume();

            String data = SHStorageManager.get(SHWeexConstants.WEEX, SHWeexConstants.DATA, "");

            if (!TextUtils.isEmpty(data)) {
                String name = SHStorageManager.get(SHWeexConstants.WEEX, SHWeexConstants.NAME, "");

                try {
                    JSONObject jsonObj = JSONObject.parseObject(data);
                    Map<String, Object> params = new HashMap<>();
                    for (Map.Entry<String, Object> entry : jsonObj.entrySet()) {
                        params.put(entry.getKey(), entry.getValue());
                    }
                    wxInstance.fireGlobalEventCallback(name, params);
                } catch (Exception e) {
                    SHWeexLog.e(e);
                } finally {
                    SHStorageManager.removeFromCache(SHWeexConstants.WEEX, SHWeexConstants.DATA);
                    SHStorageManager.removeFromCache(SHWeexConstants.WEEX, SHWeexConstants.NAME);
                }
            }
        }
    }複製程式碼

然後native會在上一個頁面出現時,去快取中取得之前存入的資料和事件名,再呼叫官方提供的例項apifireGlobalEventCallback,呼叫對應的事件,並傳資料。

當native中執行了fireGlobalEventCallback這個方法,上一頁的事件監聽函式就會取得資料。

至此就完成了native中資料的反向傳遞。

2)weexA(web) > weexB(web), weexB(web) > weexA(web)

反向傳遞引數在weex的web端就更加好處理了,AB頁面都是通過連線後面拼接引數的形式進行傳遞引數,那麼反向傳參跟正向傳參還是可以按照之前的邏輯進行。

在設計api時特意在回撥中會對是否web環境做了判斷,因為H5和native在反向傳參的行為完全不同,所以判斷邏輯會在業務中進行,更方便大家在寫業務時進行不同情況不同處理。

fireGlobalEvent('getConpon', {
    id: '3323',
  }, function () {
  if (web) {
      openUrl('/a.html?id=' + '3323');
  } else {
    navigator.pop();
  }
})複製程式碼

相關文章