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单页面路由方式不太同样,有点像伪路由。由于历史栈内的页面所有都真实的存在于当前页面上,嘻嘻,证据以下图: 框架
分析异步
而查看页面代码能够知道,每一个页面不过是被 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 传参三个方向给出了对应的传参方案并分析了各自优劣和适用场景,笔者能力有限,有更多方案的同窗欢迎在评论提出,若发现问题的,也但愿不吝赐教,谢谢!!