Ionic3 导航分析

在刚接触ionic的时候,我觉得导航不太好理解,主要是ionic的导航方式和我们之前接触的路由导航方式不太一样。之前接触的路由,基本上都是根据不同的url加载不同的内容,比如最基本的,根据url的不同加载不同的html文件;或者像React中根据不同的url加载不同的组件,这种导航方式很直接,也非常方便理解。但ionic的导航系统使用起来感觉不是这样的,或许原理是类似的吧,但这里只讨论ionic中导航的使用。本文将通过一个例子,讲解ionic中导航的使用。
基本流程如下:登录 》 tabs 》退出重新到登录

效果图
首次登录



登录之后进入到tabs界面



点击退出功能重新回到登录界面
image.png

uiRouter

路由是前端构建单页面应用(SPA)必不可少的一部分,AngularJS1.x中有两种路由实现,一个是内置的ngRouter,还有一个是基于 ngRoute 开发的第三方路由模块uiRouter。这里为什么要提uiRouter?因为就自我感觉而言uiRouter 和 ionic导航在使用方式上有点像,特别是从它们提供的指令这一层来考虑。如果你没有了解过Angular4中的路由,其实也可以简单看看uiRouter的使用,不需要了解的多详细,仅仅理解它的那个指令的使用方式就可以了。

ui-router官网


有关于uiRouter更详细的介绍,可以看看这篇文章 Angular导航
点击对应链接,触发 $state.go('x'x'x') 方法,uiRouter根据state找到对应的视图并加载在ui-view容器中,实现界面的变化。一定要注意,是将视图模板加载到 ui-view容器中,没有ui-view容器,是不能够显示对应的模板内容的。

NavController

ionic中的导航也是类似的,至少从指令这一层次来讲基本上类似的。在uiRouter中,通过<ui-view>这个指令来展示内容,也就可以将<ui-view>看作是一个容器,好了这个容器,uiRouter没办法将内容展示到界面。而ionic中也有一个类似的指令<ion-nav>。<ion-nav> 在ionic中就是一个内容的容器,没有这个容器什么也看不到,<ion-nav> 可以 覆盖在 <ion-nav> 上面, 可以通过给 <ion-nav> 添加唯一标识来区别多个<ion-nav>。 而对于界面的跳转,Ionic提供了一套自己的API,最常用的就是NavController,这个类中几乎包含了与导航有关的所有方法,通过这个接口可以满足绝大部分需求。总的来说就是:<ion-nav> 是界面的容器,然后通过NavController提供的API实现界面的跳转,从而实现导航效果。

实现过程

从整体上来看,有两个界面:登录界面、Tab界面。其中登录界面作为一个独立的 界面,tab界面中的某个tab上有退出当前用户功能,退出之后重新跳回到登录界面,很常见的一个流程。

登录界面



Tab界面,其中在Person这个tab页面有退出登录功能


主要代码

app.html 。可以把这里当作是整个应用的起点,也就是说在 app.html中必须要有一个<ion-nav> ,并且是作为整个应用的 根 <ion-nav>。

<ion-nav [root]="rootPage" ></ion-nav>
//代码只有一行,其中 root 是 <ion-nav>中的一个属性指令,它的值是对应的一个 组件,但是 ionic3中支持懒加载,所以可以是一个字符串(有关于懒加载具体的可以看Angular和ionic的文档)

//root 表示的是默认加载的界面,也就是应用一启动就加载哪个界面

app.component.ts 。只结束一些主要的逻辑,我们希望实现这样的功能:当用户已经登录了,点开应用的 时候跳到tab界面,没有登录的时候,点开应用跳到登录界面。!this.nativeService.isLogin(false) 是我自己实现的一个函数,用于判断用户是否登录。

// 加载tabs页面之前先判断是否登录(就是进入系统时展示登录界面)
if (!this.nativeService.isLogin(false)) {
  this.rootPage = 'LoginPage';
} else {
  this.rootPage = 'TabsPage';
}

login.html。主要就是一些布局,这个文件没什么特殊之处。

login.ts。登录功能的逻辑代码,包括点击登录之后界面需要进行跳转,涉及到导航。

  //在构造函数中注入了 NavController
  constructor(private navCtrl: NavController,
              private navParams: NavParams,
              private formBuilder: FormBuilder,
              private viewCtrl: ViewController,
              private events: Events,
              private httpService: HttpService,
              private storageService: StorageService,
              private nativeService: NativeService) {
  }

  login(value) {
    this.nativeService.showLoading('loading...');

    this.httpService.login('/oauth/token', value).then(result => {
      if (!result || !result.access_token) {
        this.nativeService.alert(result.message, '登录失败');
        this.storageService.remove(ACCESS_TOKEN);
        return;
      }

      this.storageService.write(ACCESS_TOKEN, result.access_token);

      this.navCtrl.setRoot('TabsPage');
    }).catch(error => {
      DEBUG && console.log('访问错误:' + error);
      this.nativeService.hideLoading();
      this.nativeService.showToast('用户名或密码错误');
    });
  }

仅仅点击登录这部分功能。登陆成功后,先将ACCESS_TOKEN(可用于判断用户是否登录)存到localstorage中,然后执行界面跳转。界面跳转的实现代码如下:

this.navCtrl.setRoot('TabsPage');

表示将 TabsPage 设置为整个应用的跟界面,也就是说将 TabsPage 代表的界面放到 app.html中的<ion-nav>容器中。

tabs.html。这个界面中用到了ionic提供的 <ion-tabs>组件,这是ionic封装好的,直接用就可以了。

<ion-tabs #mainTabs>
  <ion-tab [root]="HomePage" tabTitle="Home" tabIcon="home"></ion-tab>
  <ion-tab root="ExamplePage" tabTitle="Example" tabIcon="information-circle"></ion-tab>
  <ion-tab [root]="PersonalPage" tabTitle="Personal" tabIcon="contacts"></ion-tab>
  <ion-tab [root]="SegmentsPage" tabTitle="Segments" tabIcon="contacts"></ion-tab>
</ion-tabs>

可以看到在<ion-tabs>下面有4个tab,表示我们在上面图片中看到的4个tab界面。

接下来重点看看退出登录那个Tab界面
personal.html。只有一个按钮,点击退出当前账号

<ion-header>
  <ion-navbar>
    <ion-title>personal</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <button ion-item (click)="exitSoftware()" hideWhen="ios" detail-none>
    <ion-icon name="log-out" item-left color="danger"></ion-icon>
    退出当前账号
  </button>
</ion-content>

personal.ts。对应的退函数如下,点击退出的时候,先弹出一个提示框,当用户确定退出的时候,清除localStorage里面的信息,然后跳转到登录界面。

  exitSoftware() {
    this.alertCtrl.create({
      title: '确认退出?',
      buttons: [{text: '取消'},
        {
          text: '确定',
          handler: () => {
            localStorage.clear();
            this.navCtrl.parent.parent.setRoot('LoginPage');
            // this.platform.exitApp(); 杀死app进程
          }
        }
      ]
    }).present();
  }

这里有一行代码需要注意

 this.navCtrl.parent.parent.setRoot('LoginPage');

这行代码代表什么意思呢?this.navCtrl.parent 代表当前<ion-nav>的父级<ion-nav>,this.navCtrl.parent.parent就代表父级的父级。含义已经知道了,但是为什么要这样写呢?
刚刚在前面已经说过,一个 <ion-nav> 可以 覆盖在 另外一个 <ion-nav> 上面,被覆盖方作为父级,覆盖方作为子级。有人可能会说,这里并没有用到<ion-nav> ,是的,可是这里用到了<ion-tabs>,这两者的功能是类似的,从代码中也可以看出来,都有一个root属性。并且<ion-tabs>就相当于是<ion-tab>的父级。
所以,根据以上的特性就可以分析出来,在 personal.ts 中,this.navCtrl 代表就是当前的那个Tab,叶就是

<ion-tab [root]="PersonalPage" tabTitle="Personal" tabIcon="contacts"></ion-tab>

也就是说 this.navCtrl.parent 代表的是 <ion-tabs>。然后,<ion-tabs> 依附在 app.html中的 <ion-nav>上,所以 this.navCtrl.parent .parent代表的就是 app.html中的 <ion-nav>,也就是整个应用的根 <ion-nav>。this.navCtrl.parent.parent.setRoot('LoginPage'),/就是将该应用的根 <ion-nav> 展示界面设置为 LoginPage。

如果你不这么做,而是在 personal.ts 中直接setRoot

  exitSoftware() {
    this.alertCtrl.create({
      title: '确认退出?',
      buttons: [{text: '取消'},
        {
          text: '确定',
          handler: () => {
            localStorage.clear();
            this.navCtrl.setRoot('LoginPage');
            // this.platform.exitApp(); 杀死app进程
          }
        }
      ]
    }).present();
  }

你会看到这样的结果:登录界面依附在 tabs 上,这显然不是我们需要的结果

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,724评论 6 342
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,398评论 25 707
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,350评论 0 17
  • 姓名:母光艳 公司:宁波贞观电器 第235期,利他二组 【日精进打卡第170天】 【知-学习】 诵读《六项精进》大...
    母光焱阅读 186评论 0 0