项目:露营伴侣(Camper Mate) - 第三课:新建一个标签页布局
本课中我们给应用创建一个基本的布局,也就是一个标签页布局。标签页的工作方式跟之前的页面有点不一样,页面只是标签页的持有者,但是实际内容是你导入进来的其他标签页面。实际工作中看到的话你就会知道了。
首先,我们得创建三个子标签来持有应用的不用页,但是实际上我们有一个额外的标签也是用于持有Quick List功能的。
我们先从持有所有标签页的Home页开始。
>修改 src/pages/home/home.html 为如下:
<ion-tabs>
<ion-tab [root]="tab1Root" tabTitle="Location" tabIcon="navigate"></ion-tab>
<ion-tab [root]="tab2Root" tabTitle="My Details" tabIcon="person"></ion-tab>
<ion-tab [root]="tab3Root" tabTitle="Camp Details" tabIcon="bookmarks"></ion-tab>
</ion-tabs>
如你所见,此处布局非常简单。我们用到了接着通过设置了一些标签页。我们然后将这些标签页的root属性设置了一个表达式,这些表达式马上会在home.ts上定义。这个表达式将是标签页用来容纳的内容。我们也添加了title和icon用来展示在标签界面上。
现在,我们来看看类定义。
>修改 src/pages/home/home.ts 为如下:
import { Component } from '@angular/core';
import { LocationPage } from '../location/location';
import { MyDetailsPage } from '../my-details/my-details';
import { CampDetailsPage } from '../camp-details/camp-details';
@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
tab1Root: any = LocationPage;
tab2Root: any = MyDetailsPage;
tab3Root: any = CampDetailsPage;
constructor(){
}
}
我们导入了所有要在标签页中展示的页面,然后设置好了模板中要用到的表达式。第一个展示标签页展示的是LocationPage。
我们的标签页基本上是设置好了(万岁!),但是还没到休息时间 — 我们需要给每个标签页设置好类。我们先从Location页开到。Location页面有一个地图,一些按钮给用户设置他们位置,给用户启动回家导航。
>修改 src/pages/location/location.html 为如下:
<ion-header>
<ion-navbar color="primary">
<ion-title>
<img src = "assets/images/logo.png" class="logo" />
</ion-title>
<ion-buttons start>
<button ion-button icon-only (click)="setLocation()"><ion-icon name="pin"></ion-icon></button>
</ion-buttons>
<ion-buttons end>
<button ion-button icon-only (click)="takeMeHome()"><ion-icon name="walk"></ion-icon></button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<div #pleaseConnect id="please-connect">
<p>Please connect to the Internet...</p>
</div>
<div #map id="map"></div>
</ion-content>
允许我们在应用顶部添加一个页首用于持有按钮,标题甚至在需要的时候直接整合Ionic导航系统的后退按钮。我们给他添加了primary属性用我们的primary颜色对他定制样式,这个颜色在app.variable.scss定义好了(我们后面会配置)。
在这个navbar里面我们用到了,他就是用来展示当前页标题和logo的。我们给他提供了start属性,这样按钮都会从左边开始排列,如果是right属性的话就是从右边开始排列。我们在两边各放置了一个按钮用处触发“设置位置”和“带我回家”功能。
最后,内容区域只有一个div我们在其中添加了#map — 这让我们后面可以在类中获取到这个节点。同时div稍后也会作为我们Google Map的容器。我们添加了另一个div用来展示用户的连接信息告诉用户是否联网了(稍后实现这个)。
现在,我们来看看location页的类定义。
>修改 src/pages/location/location.ts 为如下:
import { NavController, Platform, AlertController } from 'ionic-angular';
import { Component, ElementRef, ViewChild } from '@angular/core';
import { Geolocation } from 'ionic-native';
import { GoogleMaps } from '../../providers/google-maps';
import { Data } from '../../providers/data';
@Component({
selector: 'page-location',
templateUrl: 'location.html'
})
export class LocationPage {
@ViewChild('map') mapElement: ElementRef;
@ViewChild('pleaseConnect') pleaseConnect: ElementRef;
latitude: number;
longitude: number;
constructor(public navCtrl: NavController, public maps: GoogleMaps, public platform: Platform, public dataService: Data, public alertCtrl:AlertController) {
}
ionViewDidLoad(): void {
}
setLocation(): void {
}
takeMeHome(): void {
}
}
虽然我们设置了一些东西,但是还不足以继续。我们从Ionic Native中导入了稍后会用到的Geolocation,同样也导入了Google Maps和Data服务(稍后创建)。
我们把所有这些服务都注入到构造器中通过添加public将他们设置为成员变量,我们也定义了两个变量latitude和longitude,将用于持有用户位置。最后,我们添加了两个模板中按钮要调用的函数,目前还没有实现。
这里最奇怪的是使用了@ViewChild。你可以用他来获取模板中的元素的引用。所以,如果我们这样:
@ViewChild('map') mapElement: ElementRef;
他将会去location.html模板中查找一个含有#map的元素。如果找到了的话,将会返回一个ElementRef也就是那个元素的引用。在这个实例中,我们将这个引用指向到了mapElement。稍后,我们会把这个引用传递给Google Maps提供者。重点记住,这一步需要在ionViewDidLoad()方法里面做,因为这个函数只会在DOM(页面元素)完全加载完成的时候运行一次。
现在,我们移步到Camp Details页。
> 修改 src/pages/camp-details/camp-details.html 页面为如下:
<ion-header>
<ion-navbar color="primary">
<ion-title>
<img src="assets/images/logo.png" class="logo" />
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-card>
<ion-card-header>
Camp Details
</ion-card-header>
<ion-card-content>
Update this form with the details of your current camp so you have an
easy reference for later.
</ion-card-content>
</ion-card>
<ion-list no-lines>
<ion-item>
<ion-label stacked>Gate Access Code</ion-label>
<ion-input type="text"></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>Ammenities Code</ion-label>
<ion-input type="text"></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>WiFi Password</ion-label>
<ion-input type="text"></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>Phone Number</ion-label>
<ion-input type="text"></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>Departure Date</ion-label>
<ion-datetime displayFormat="DD/MM/YYYY"></ion-datetime>
</ion-item>
<ion-item>
<ion-label stacked>Notes</ion-label>
<ion-textarea type="text"></ion-textarea>
</ion-item>
</ion-list>
</ion-content>
第一个就是添加了navbar,你已经知道他是怎么工作的。我们也用了一个为页面创建了一个小小的页首区用于描述页面上干嘛用的,这只是一个纯粹的装饰品。然后我们在一个列表里面有大量的输入域。不是用的标准HTML语法:
<input type="text" />
我们使用的是Ionic提供的,但是接受的是同样的类型(你应该注意到了最后一个是)。我们提供了stacked属性,这个属性让在输入域上“堆栈”标签,但是Ionic默认给输入域提供的样式有很多。目前我们只是给输入域添加了标签,稍后回来我们会其他一些其他的东西这样我们就可以获取用户的输入。
同时这里我们也有用到,这是Ionic提供的内置的日期和时间选择器。
现在没有什么不同的事情会发生,我们还是先来创建页的类定义吧。
> 修改 src/pages/camp-details/camp-details.ts 如下:
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Data } from '../../providers/data';
@Component({
selector: 'page-camp-details',
templateUrl: 'camp-details.html'
})
export class CampDetailsPage {
constructor(public navCtrl: NavController, public formBuilder: FormBuilder,public dataService: Data) {
}
saveForm(): void {
}
}
这里跟之前不同的是我们从Angular导入了FormBuilder和Validators。就跟上面说的一样,我们将编辑稍后创建的输入域来做一些实际的事情,这就是Form Builder(和ControlGroup)用来介入的地方了。Form Builder允许你创建和管理表单,Vlidators可以附加到指定的输入域以确保输入的是一个有效值(即,如果需要输入的是邮件地址,手机号等)。我们稍后再深入。
我们也添加了一个saveForm函数稍后用来保存用户在表单中的输入值。现在,我们移步到My Details页,跟这个页面很像。
> 修改 src/pages/my-details/my-details.html 页面为如下:
<ion-header>
<ion-navbar color="primary">
<ion-title>
<img src = "assets/images/logo.png" class="logo" />
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-card>
<ion-card-header>
My Details
</ion-card-header>
<ion-card-content>
Update this form with your details so you have an easy reference for
later.
</ion-card-content>
</ion-card>
<ion-list no-lines>
<ion-item>
<ion-label stacked>Car Registration</ion-label>
<ion-input type="text"></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>Trailer Registration</ion-label>
<ion-input type="text"></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>Trailer Dimensions</ion-label>
<ion-input type="text"></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>Phone Number</ion-label>
<ion-input type="text"></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>Notes</ion-label>
<ion-textarea type="text"></ion-textarea>
</ion-item>
</ion-list>
</ion-content>
没啥好解释的,只是有几个不同的输入域,他跟Camp Detail模板简直就是一毛一样。直接去类定义吧。
> 修改 src/pages/my-details/my-details.ts 如下:
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Data } from '../../providers/data';
@Component({
selector: 'page-my-details',
templateUrl: 'my-details.html'
})
export class MyDetailsPage {
constructor(public navCtrl: NavController, public formBuilder: FormBuilder, public dataService: Data) {
}
saveForm(): void {
}
}
同样,这个跟Camp Details页基本一毛一样的。为这个枯燥的结局道个歉,但是对于布局部分来讲,这就是全部了,下一刻我们将近距离观察Form Builder以及让我们让你合理的输入。