Ionic3 中父頁面給子頁面傳遞參數很是容易,使用框架提供的 navParams 來實現就好了,可是反過來子頁面給父頁面傳遞就沒那麼容易了,由於在路由的 navController 裏面的 pop 函數並不支持傳參數,使得前面的方法沒有用了(表面上是,實際上仍然有用,詳細看正文),這個時候就須要別的手段來達到咱們的目的了,故本文主要將對 Ionic3 中子頁面向父頁面傳參問題提供筆者經常使用的幾種解決方案,如有問題或更多建議,歡迎各位同僚下方評論,共同進步!es6
在 Ionic 中如何作到頁面與頁面間的通訊?這裏給出三種方向:路由傳參,事件傳參,service 傳參。因爲三個方向各自又有不一樣的實現,且每種方案適應的場景都不同,下面就會從實現,優缺點,適應場景這幾個方面來比較一下這幾個方案,最後各位看官老爺們各取所需。ajax
假如你還不知道Ionic3的路由傳值的話,請戳 NavController 瞭解一下。typescript
好了正文開始,這裏要用的就是navParams,前面已經說了,在頁面的pop操做裏面是不容許傳值的,那如何作到用navParams傳值。這裏給出兩種方案api
// 本文出現navCtrl都指代navContronller
// 語法不必定正確,請根據自身代碼進行修正
<!--父頁面-->
public a = 'a';
navCtrl.push('childrenPage', {
parent: this
})
<!--子頁面-->
parent = navParams.get('parent');
parent.a = 'change from childe';
<!--父頁面-->
console.log(a) // change from childe
// 你也能夠直接調用父頁面的方法
複製代碼
歷史棧promise
Ionic3 的路由有個歷史棧的概念,相信知道棧的同窗確定都很熟悉這個,其實就是和棧同樣的操做,app開始在根頁面的時候,這個歷史棧只有1個頁面,就是你的根頁面,以後每當使用navController的push方法到一個新的頁面的時候,歷史棧把新的頁面加入進來,pop的時候就把那個頁面從歷史棧中彈出。瀏覽器
路由app
Ionic3 的路由機制比較「神奇」,和別的常見的Vue-Router或Angular單頁面路由方式不太同樣,有點像僞路由。由於歷史棧內的頁面所有都真實的存在於當前頁面上,嘻嘻,證據以下圖: 框架
能夠看到,個人頁面實際上通過了HomePage —> parentPage —> childPage跳轉,如今在childPage了,也就是說歷史棧內有這三個頁面,而在瀏覽器內能夠看到三個頁面都真實的存在。分析異步
而查看頁面代碼能夠知道,每一個頁面不過是被 InoicPage 裝飾器修飾過的 Angular 的組件而已,那麼就能夠經過獲取組件的實例來改變組件的狀態。結合上面路由的狀況咱們知道:即便到了子頁面,咱們的父頁面或者說父組件沒有被destroy的(可自行驗證)。因此在子頁面中,咱們是能夠經過拿到歷史頁面的實例來對其進行操做的。最後咱們再整理一下思路:這裏利用navParams來傳遞父頁面自己到子頁面中,而後子頁面獲取到父頁面來對其進行操做,經過這個方式來達到傳遞參數的目的。ionic
優勢
使用方式簡單高效,甚至能夠規避傳遞參數這一個步驟直接在子頁面對父頁面進行操做(不推薦)。
缺點
涉及對父頁面的操做少且不復雜的場景,且僅推薦父 —> 子間使用,並且但願在使用時聲明一個明確的參數名稱以代表父子頁面之間的聯繫,提高代碼的可維護性。
<!--這裏是網上常見版本,但筆者不太喜歡此版本-->
<!--父頁面-->
public a = 'a';
// 必須使用箭頭函數,若不使用,此法將會失效
public parentPromise = (childrenParams) => new Promis((resolve, reject) => {
// 這裏能夠作你想利用回傳的參數想作的事
this.a = childrenParams;
console.log('childe change work: ', this.a);
resolve();
});
navCtrl.push('childrenPage', {
parentPromise: this.parentPromise
});
<!--子頁面-->
parentPromise = navParams.get('parentPromise');
parentPromise('change from childe').then(() => {
// 此時會打印 childe change worke: change from childe
navCtrl.pop();
})
複製代碼
預備知識
這裏代碼稍微有點繞,須要你瞭解的知識有 Promise、箭頭函數、TypeScript,假如你不太瞭解,請戳Promise、箭頭函數,瞭解事後再看接下來的內容。
分析
注意是在子頁面執行 parentPromise 內的代碼,代碼之因此可以跑成功,緣由其實和上面第一種用法的緣由是同樣的,能夠說利用的原理都是同樣,可是和第一種略微不一樣的是:前者是顯示的傳遞 this 給子頁面,控制權所有交給了子頁面,後者是利用箭頭函數將 parentPromise 的 this 綁定在父頁面上,控制權在父頁面上。
優勢
缺點
我想說
此段代碼是有問題的。並非結果有問題,而是代碼的實際執行行爲與代碼表現的執行預期出現的差別的問題。筆者嘗試對 parentPromise 解讀時的預期是:子頁面傳入參數 —> 子頁面返回 —> 父頁面得到參數而後作相關操做,可是實際執行行爲如以前的分析根本不是這樣的:子頁面傳入參數 —> 得到參數而後作相關操做 —> 子頁面返回,能夠發現實際執行過程當中 parentPromise 內部的 Promise 實際上是沒有太多意義的,在子頁面徹底能夠直接回調而後執行 pop 的操做。這就是筆者對這段代碼不太喜歡的緣由。 這段下面給出筆者的「改進版」供讀者評論。
<!--父頁面-->
public a = 'a';
// 不使用箭頭函數依舊可使用
public popWithParams(childNavCtrl: navController, childeParams: any) {
// 回到父頁面再操做
childNavCtrl.pop().then(function() {
this.a = childrenParams;
console.log('childe change work: ', this.a);
}
};
navCtrl.push('childrenPage', {
popWithParams: this.popWithParams
});
<!--子頁面-->
popWithParams = navParams.get('parentPromise');
popWithParams(navCtrl, 'change from childe');
複製代碼
<!--此法是前二者的結合,和第二種方法更像,可是用法更簡單,也更容易理解-->
<!--父頁面-->
public a = 'a';
public parentCallback = (childeParams: any) => {
// this被綁定在父頁面
// 僅當此處代碼爲異步時(例:數據須要ajax獲取),考慮法2傳遞Promis的用法
this.a = childrenParams;
console.log('childe change work: ', this.a);
};
navCtrl.push('childrenPage', {
parentCallback: this.parentCallback
});
<!--子頁面-->
popWithParams = navParams.get('parentPromise');
parentCallback('change from childe');
navCtrl.pop()
複製代碼
優勢
使用簡單,容易理解,且父子頁面耦合也比較低控制權在父頁面。
缺點
同前二者。
<!--父頁面-->
constructor(public events: Events) {}
ngOnInit() {
// 訂閱來自子頁面的事件
events.subscribe('childParams:doWhenInit', (childParams) => {
console.log(childParams); // params from childPage
});
}
<!--子頁面-->
constructor(public events: Events) {}
getParams() {
this.events.publish('childParams:doWhenInit', 'params from childPage');
}
複製代碼
預備知識
此爲 Ionic 提供的事件支持,詳細請戳 Ionic Events 。
優勢
缺點
這兩種方法都須要搭配 Service 結合,思路和 Ionic 提供的 Events 相似,此處很少作研究了,感興趣的同窗能夠看看相關內容。
<!--pageParamsManagerService-->
// 可在全應用範圍內被訪問及改變
public a = 'no change';
<!--父頁面-->
import 'pageParamsManagerService' from './pageParamsManagerService'
constructor(public ppmService: pageParamsManagerService) {}
// 注意不可放在 onInit 或 ionViewDidLoad鉤子內,由於 push 到子頁面時父頁面並未銷燬, pop 回來時不會執行這兩個鉤子
ionViewWillEnter() {
// 第一次進入:no change;
// 子頁面pop進入:change from childePage
console.log(this.ppmService.a);
}
<!--子頁面-->
import 'pageParamsManagerService' from './pageParamsManagerService'
constructor(public ppmService: pageParamsManagerService) {
// 改變公共變量
this.ppmService.a = 'change from childePage';
}
複製代碼
預備知識
Angular 應用裏有個 Service 的概念,通常來講 Service 都是單例模式且在全應用級別做用域均可訪問(此處不作過多探討),故咱們能夠利用這個特性來達到咱們的傳參目的。
優勢
缺點
咱們從路由傳參、事件傳參、service 傳參三個方向給出了對應的傳參方案並分析了各自優劣和適用場景,筆者能力有限,有更多方案的同窗歡迎在評論提出,若發現問題的,也但願不吝賜教,謝謝!!