项目总结之Ionic的页面跳转(ionic中的popTo()方法)

目前app项目的框架构成是angular4.0+ionic3.0,在做一个功能的时候需要复杂的页面跳转,所以在此总结一下。
之前使用了很笨的一种方法,导致扩展性很差,近期又发现了一种新的方法,很简洁实用。三个方法我都写一下以实现对比记忆。
不过在讲ionic中的popTo()方法之前,先看一下Ionic的NavController的定义
NavController概述
NavController是导航控制器组件的基类,如Nav和Tab。 您可以使用导航控制器导航到应用程序中的页面。 在基本级别,导航控制器是表示特定历史(例如,Tab)的页面的数组。 可以通过按压和弹出页面或在历史记录中的任意位置插入和删除这些数组来操纵整个应用程序。

当前页面是数组中的最后一个页面,或者堆栈的顶部,如果我们想到这样的话。 将新页面推入导航堆栈的顶部会导致新页面动画化,而弹出当前页面则将导航到堆栈中的上一页。
除非您使用像NavPush这样的指令,或者需要特定的NavController,否则大多数情况下,您将注入并使用最接近的NavController的引用来操作导航堆栈。

方法1
router.ts

import { NavController } from "ionic-angular";
constructor(
    public navCtrl: NavController,
 ) { }
  removePage(startIndex,startIndex) {
       this.navCtrl.remove(startIndex, removeLength, {
          animate: false
       });
   }      

这个方法中的this.navCtrl.remove(startIndex, removeLength, { animate: false });中startIndex是从第几个页面开始, removeLength表示移除几个页面 这个是封装的公用的方法,下面是我在另外一个页面使用的时候

 // 页面跳转
  toPage(page) {
    this.router.removePage(page, this.navCtrl.length() - page);
  }
  this.toPage(2);

例如A --> B --> C --> D --> E 我从A页面经过B、C、D页面最后到了E页面
那么this.navCtrl.length()表示页面的总长度5 page为2时, this.router.removePage(2, 3); 就是从第二个页面往后移除3个页面,我在E页面调用了这个方法,就是从E页面回到了B页面,而且这个时候C、D、E这三个页面都移除掉了,this.navCtrl.length()这个时候长度变成了2,也就是只有两个页面了,removePage移除页面。

这个方法很笨, this.toPage(num)中的num必须要自己计算出来,而且A和E之间有时候会有一些特殊情况,中间可能会多出几个页面,当出现特殊情况时还得从这些特殊的页面传递参数到最后的E页面,这样到了E页面我们才能知道经过了多少页面。很麻烦。不过,现在不用了,因为有更好的,请看方法2

方法2
封装的公用的方法

// 返回特定的页面并且关闭中间的页面
  toPage(page: string){
    let views = this.config.navCtrl.getViews();
    for (let i = 0; i < views.length; i++) {
      if (views[i].name == page) {
        this.config.navCtrl.popTo(this.config.navCtrl.getByIndex(i));
      }
    }
  }

我们来分析一下这个方法this.config.navCtrl.getViews();中的this.config.navCtrl相当于方法1中的this.navCtrl。
我们还是以A --> B --> C --> D --> E为例子来具体分析一下
this.config.navCtrl.getViews()这个方法获取了从A到E这个5个页面的页面名称和一些其他的
我们看一下第一个页面A中的数据,其中有index,name 从index:0可以获取到当前A页面所处的位置(第一个页面) name可以获取到页面的名称 等等

if (views[i].name == page) {
     this.config.navCtrl.popTo(this.config.navCtrl.getByIndex(i));
 }

这个this.config.navCtrl.getByIndex(i)为了得到在navCtrl记录的在module.ts注册的页面信息,有人会问我直接用传进来的参数page不就行了这样写 this.config.navCtrl.popTo(‘A’),答案是不可以的,注意我们传进来的是一个字符串,而this.config.navCtrl.getByIndex(i)得到的是是一个ViewController 如下:

0: ViewController
component: ƒ HomeComponent(user, funcs, modalCtrl, homeService, uploadService, navCtrl, config, api, router, events, storage, tabs, statusBar, keyboard, app, callNumber)
data: {}
didEnter: EventEmitter {_isScalar: false, observers: Array(0), closed: false, isStopped: false, hasError: false, …}
didLeave: EventEmitter {_isScalar: false, observers: Array(0), closed: false, isStopped: false, hasError: false, …}
id: "t0-0-0"
index: (0)
instance: HomeComponent {user: User, storage: Storage, navCtrl: Tab, modalCtrl: ModalController, config: Config, …}
isOverlay: false
name: (A)
readReady: EventEmitter {_isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …}
willEnter: EventEmitter {_isScalar: false, observers: Array(0), closed: false, isStopped: false, hasError: false, …}
willLeave: EventEmitter {_isScalar: false, observers: Array(0), closed: false, isStopped: false, hasError: false, …}
willUnload: EventEmitter {_isScalar: false, observers: Array(0), closed: false, isStopped: false, hasError: false, …}
writeReady: EventEmitter {_isScalar: false, observers: Array(0), closed: false, isStopped: false, hasError: false, …}
_cmp: ComponentRef_ {_view: {…}, _viewRef: ViewRef_, _component: HomeComponent, _elDef: {…}, hostView: ViewRef_, …}
_cntDir: Content {_config: Config, _elementRef: ElementRef, _renderer: RendererAdapter, _componentName: "content", _mode: "ios", …}
_cntRef: ElementRef {nativeElement: ion-content.content.content-ios.has-infinite-scroll.has-refresher}
_cssClass: "ion-page"
_detached: true
_emitter: EventEmitter {_isScalar: false, observers: Array(0), closed: false, isStopped: false, hasError: false, …}
_ionCntDir: Content {_config: Config, _elementRef: ElementRef, _renderer: RendererAdapter, _componentName: "content", _mode: "ios", …}
_ionCntRef: ElementRef {nativeElement: ion-content.content.content-ios.has-infinite-scroll.has-refresher}
_isHidden: true
_nav: Tab {_config: Config, _elementRef: ElementRef, _renderer: RendererAdapter, _componentName: undefined, parent: Tabs, …}
_state: 3
_ts: 1558097069163
_zIndex: 101
__proto__: Object

所以请注意popTo的用法
下面是对getViews()方法的官网解释:

(method) NavController.getViews(): ViewController[]
Returns the current stack of views in this nav controller.
@returns — the stack of view controllers in this nav controller.

下面是对popTo方法的官网解释

/**
     * @hidden
     * Pop to a specific view in the history stack. If an already created
     * instance of the page is not found in the stack, then it'll `setRoot`
     * to the nav stack by removing all current pages and pushing on a
     * new instance of the given page. Note that any params passed to
     * this method are not used when an existing page instance has already
     * been found in the stack. Nav params are only used by this method
     * when a new instance needs to be created.
     *
     * @param {Page|string|ViewController} page The component class or deeplink name you want to push onto the navigation stack.
     * @param {object} [opts={}] Nav options to go with this transition.
     * @returns {Promise} Returns a promise which is resolved when the transition has completed.
     */
    abstract popTo(page: Page | string | ViewController, opts?: NavOptions, done?: TransitionDoneFn): Promise<any>;

OK了,以为就这样就可以了,在本地电脑浏览器跑的很溜,打包之后在手机上试的时候傻眼了,点击之后没有反应,没有反应,这是什么情况?why? 于是手机连接到电脑上进行调试的时候发现问题了

扫描二维码关注公众号,回复: 9368915 查看本文章
        let views = this.config.navCtrl.getViews();
        for (let i = 0; i < views.length; i++) {
          if (views[i].name == page) {
            this.config.navCtrl.popTo(this.config.navCtrl.getByIndex(i));
          }
         }

打包之后,代码被压缩了,都在压缩包里,于是许多参数和变量都被替换成了a,b,c,s,n等等这样的变量(打包的时候替换生成的),这个时候在执行if (views[i].name == page) 这一步的时候views[i].name都变成了l,n等类似于打包时这样的变量,所以if (views[i].name == page)肯定不会为true,也就执行不了this.config.navCtrl.popTo(this.config.navCtrl.getByIndex(i));
那怎么解决这个问题呢?百度找了找没找到,于是翻墙google了一下,终于找了解决方法。方法三

方法三

toPage(page) {
    let views = this.config.navCtrl.getViews();
    for (let i = 0; i < views.length; i++) {
      if (views[i].component == page) {
        this.config.navCtrl.popTo(this.config.navCtrl.getByIndex(i));
        return;
      }
    }

    this.config.navCtrl.popToRoot().then(
      ()=> {
        this.config.navCtrl.push(page);
      }
    );
  }

相比于方法二变动的地方:

1.有toPage(page)传入的参数page不再是字符串了,而是一个定义的class名了也可以说是page(可以参考上面的popTo()官网解释),类似这样的export class MyHome {},传入是MyHome,而且在使用toPage方法的页面还需要import MyHome

2.if (views[i].name == page) 被替换成了if (views[i].component == page) ,name打包之后就换成变量了,所以这里被替换成了component,其实这里的component获取的是跳转经过的页面的信息,这个时候传入page就可以匹配上了。完美解决

感觉自己解决问题的能力还需要提高,特别是遇到一个问题,怎么能够快速定位到问题的关键,怎么能够快速的搜到这个问题或者说我搜的时候怎么能够准确快速的描述清楚问题,这很重要,加油吧,努力着,从未放弃!

发布了130 篇原创文章 · 获赞 103 · 访问量 26万+

猜你喜欢

转载自blog.csdn.net/xiaolinlife/article/details/90298881