Ionic3首次项目实践记录

标签(空格分隔): Angular Ionic

Ionic3踩坑

1. 路由懒加载(lazy load)

如果设置了懒加载,就必须全部懒加载(包括TabsPage),否则会出现路由跳转后tabs消失的情况。

2. 通过ts来返回tabs的首页:

注意必须通过 this.app.getRootNav().setRoot('tabs');,不能到home,否则,tabs会消失。

参见stackoverflow | Issues

import { App } from "ionic-angular";

@IonicPage({ name: [page-name] })
@Component({
...
}) export class DemoPage {
constructor(
private app: App
) { } goBack() {
this.app.getRootNav().setRoot('tabs');
}
}

3. 隐藏子路由里面的tabs,可以通过配置app.module.tas里面的 tabsHideOnSubPages: true实现:

@NgModule({
declarations: [
MyApp
],
imports: [
...
IonicModule.forRoot(MyApp, {
tabsHideOnSubPages: true
}),
...
],
...
})

4. 自定义表单验证

不用angular@Directive()装饰器的方法,直接定义一个类,定义静态方法:

import {FormControl} from "@angular/forms";
import {G} from "../services/data-store.service"; export class MyValidators {
private static isEmptyInputValue(value) {
// we don't check for string here so it also works with arrays
return value == null || value.length === 0;
} /**
* 与指定值相等
* @param {string} equalCtrl 指定FormControl健名
* @returns {(ctrl: FormControl) => {equalTo: {valid: boolean}}}
*/
static equalTo(equalCtrl: string) {
return (ctrl: FormControl) => {
if (this.isEmptyInputValue(ctrl.value)) return null; const _equalCtrl = ctrl.root.get(equalCtrl);
const valid = (_equalCtrl && (ctrl.value === _equalCtrl.value)); return valid ? null : {
equalTo: {
valid: false
}
}
}
}
}

调用方法(FormBui;der):

import {Component, EventEmitter, Output} from "@angular/core";
import {FormBuilder, FormGroup, Validators} from "@angular/forms";
import {G} from "../../../services/data-store.service";
import {AlertController} from "ionic-angular";
import {StaticDataService} from "../../../services/common/static-data.service";
import {MyValidators} from "../../../directives/my-validators.directive"; @Component({
selector: 'page-sign-up',
templateUrl: 'sign-up.html'
}) export class SignUpPage {
public form: FormGroup;
public TYPES = G.ACCOUNT_TYPES; @Output() onShow = new EventEmitter<number>(); constructor(
private formBuilder: FormBuilder,
private alertCtrl: AlertController,
private staticService: StaticDataService
) {
this.form = this.formBuilder.group({
username: ['', Validators.compose([
Validators.required,
MyValidators.mobile()
])],
password: ['', Validators.compose([
Validators.required,
Validators.minLength(6)
])],
passwordConfirm: ['', Validators.compose([
Validators.required,
MyValidators.equalTo('password')
])],
recommend: ['']
});
} }

html:

...
<ion-item>
<ion-label floating>请输入您的密码</ion-label>
<ion-input type="password" formControlName="password" name="password" class="form-control"></ion-input>
</ion-item>
<div class="error-wrap" [hidden]="form.get('password').valid || form.get('password').pristine">
<small [hidden]="!form.get('password').hasError('required')" class="error">
请输入密码
</small>
<small [hidden]="!form.get('password').hasError('minlength')" class="error">
请输入不少于6位的密码
</small>
</div> <ion-item>
<ion-label floating>请再次确认密码</ion-label>
<ion-input type="password" formControlName="passwordConfirm" name="passwordConfirm" class="form-control"></ion-input>
</ion-item>
<div class="error-wrap" [hidden]="form.get('passwordConfirm').valid || form.get('passwordConfirm').pristine">
<small [hidden]="!form.get('passwordConfirm').hasError('required')" class="error">
请确认密码
</small>
<small [hidden]="!form.get('passwordConfirm').hasError('equalTo')" class="error">
两次密码输入不一致
</small>
</div>
...

5. 父子页面通信

主要是通过NavControllerNavParams来实现。

父向子直接通过push([path], [param], [options])的第二个参数实现数据通信,在子页面中,通过NavParams获取到对应的数据。

子向父pop([options])方法却没有参数传递选项。可以通过Promise实现:

父页:

goToChild() {
new Promise((resolve, reject) => {
this.navCtrl.push('coupon', {
// 将resolve方法传递到子页中
resolve: resolve
});
}).then((data: Datas) => {
// 从子页获取到数据 赋值到当前类的属性中
this.CouponId = data.id;
this.CouponType = data.type;
this.CouponValue = data.value;
});
}

子页:

constructor(
private navParam: NavParams,
private navCtrl: NavController
) {
this.callback = this.navParam.data.resolve;
} ... goBack() {
// 为resolve传值
this.callback({ id: this.selectCoupon, type: this.selectCouponType, value: this.selectCouponValue });
this.navCtrl.pop();
}

6. 在Http通信中,参数中的+号被替换为空格的问题

参见

/**
* 解决http请求字符串中+号被替换为空格的问题
*/
export class CustomQueryEncoderHelper implements HttpParameterCodec {
encodeKey(k: string): string {
return encodeURIComponent(k);
} encodeValue(v: string): string {
return encodeURIComponent(v);
} decodeKey(k: string): string {
return decodeURIComponent(k);
} decodeValue(v: string): string {
return decodeURIComponent(v);
}
}
    // 处理undefined
for (let i in this._datas) {
if (this._datas.hasOwnProperty(i)) {
if (this._datas[i] === undefined) {
delete this._datas[i];
}
}
} Object.assign(datas, this._datas); if (!this.isGet) {
const _date = new Date(Date.parse(new Date().toString()) + CONF.ApiData.DiffTime);
datas.TimeSpan = Tools.dateTimeFormat(_date, 'yyyy-MM-dd hh:mm:ss');
} let preparedParams = new HttpParams({
encoder: new CustomQueryEncoderHelper(),
fromObject: datas
}); if (this.isGet) {
this.datas = { params: preparedParams };
} else {
this.datas = preparedParams;
}

7. Events事件订阅的使用

(个人)开发中最经典的用例,就是在app.component.ts中的ion-menu做页面跳转。由于整个项目是懒加载的,如果直接使用@ViewChild(Nav) nav: Nav;,然后通过this.nav.pus([page])会导致没有tabs,页面一刷新就不能返回了。

经过各种试验,最后发现使用Events事件订阅可以轻松解决。

首先在app.component.ts中发布事件:

import ...
@Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage:any = 'tabs'; constructor(
platform: Platform,
statusBar: StatusBar,
splashScreen: SplashScreen,
private events: Events
) { } // 通知从home页面跳转
get navTo(): Datas {
// 关闭抽屉菜单
this.menuCtrl.close('mainMenu');
return {
publish: name => {
this.events.publish('nav:to', name);
}
}
} // 抽屉菜单打开
menuOpened() {
if (CONF.UserData.IsLogin) {
// 已经登录
this.isLogin = true; this.getUserInfo(); // 获取用户信息
this.getUserFund(); // 获取用户资金账户信息 return;
} // 未登录
this.isLogin = false;
} // 前往设置
goToSetting() {
if (!this.checkLogin()) return; this.navTo.publish('setting');
} ... }

然后在home.ts中订阅事件,做跳转操作,这样就相当于在home中跳转,不会出现tabs丢失的情况:

import ...
@IonicPage({ name: 'home' })
@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(private events: Events) {
this.events.subscribe('nav:to', name => {
this.navCtrl.push(name);
});
} ...
}

未完待续...    Last updated by: Jehorn, August 14, 2018, 04:35 PM

Ionic3项目实践记录的更多相关文章

  1. 9-2、大型项目的接口自动化实践记录----递归判断两个json串是否相等

    1.已知json串构成的情况下判断 先构造一下场景,假设已经把各个数据都移除掉不对比的字段 图1 预期.实际结果,复杂接口返回多层嵌套json时,同下 图2 预期.实际结果值为:{child_json ...

  2. 9-1、大型项目的接口自动化实践记录----数据库结果、JSON对比

    上一篇写了如何从DB获取预期.实际结果,这一篇分别对不同情况说下怎么进行对比. PS:这部分在JSON对比中也适用. 1.结果只有一张表,只有一条数据 数据格式:因为返回的是dicts_list的格式 ...

  3. 8、大型项目的接口自动化实践记录----DB分别获取预期结果、实际结果

    上一篇实现数据分离升级版--从DB获取数据,以及对应的请求实现,作为一个case,还缺少了预期结果与实际结果的获取及对比.因为前面的文章已经说过接口返回值的获取及对比,所以这篇不说这块了,这篇说一下D ...

  4. 3、大型项目的接口自动化实践记录----开放API练习

    开始做实际项目前,先拿个网上的简单API练下手 一.API说明: 接口信息 接口名:京东获取单个商品价格 地址:http://p.3.cn/prices/mgets 入参:skuids=J_商品ID& ...

  5. 2、大型项目的接口自动化实践记录--接口测试简介及RequestsLibrary关键字简介

    1.接口测试简介 1)先简单介绍下接口测试,那么什么是接口测试呢? 百科的回答:接口测试是测试系统组件间接口的一种测试.接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点. 看起来有 ...

  6. 1、大型项目的接口自动化实践记录--robotframework环境搭建

    因为人力.团队技术问题,选用robotframework来做自动化,首先说下环境搭建 齐涛道长的入门教程非常棒:http://blog.csdn.net/tulituqi/article/detail ...

  7. Hangfire项目实践分享

    Hangfire项目实践分享 目录 Hangfire项目实践分享 目录 什么是Hangfire Hangfire基础 基于队列的任务处理(Fire-and-forget jobs) 延迟任务执行(De ...

  8. Hangfire项目实践

    Hangfire项目实践分享 Hangfire项目实践分享 目录 Hangfire项目实践分享 目录 什么是Hangfire Hangfire基础 基于队列的任务处理(Fire-and-forget ...

  9. MVC项目实践,在三层架构下实现SportsStore-01,EF Code First建模、DAL层等

    SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管 ...

随机推荐

  1. GetModuleFileName和获取应用程序当前目录

    原文:http://www.cnblogs.com/xuemaxiongfeng/articles/2465544.html API函数GetModuleFileName():获得应用程序目录相对路径 ...

  2. android头像上传(获取头像加剪切)

    因为项目中需要用到头像上传的功能,所以就下个Ddmo先来实现下. demo我是类似仿微信的,在一个GridView中展示所有的图片,其中第一个item可以去照相:获取到图片后再进行剪切. 图片的剪切是 ...

  3. 六、angular 生成二维码

    首先需要安装angular-qrcode : bower install monospaced/angular-qrcode npm install angular-qrcode 如何使用? 在相应的 ...

  4. ubuntu16 下安装redis 以及设置其为开机启动

    1.下载redis安装包 sudo wget http://download.redis.io/releases/redis-3.2.6.tar.gz 2.解压 tar -zxvf  redis-3. ...

  5. spring+quarts常见问题

    javax/transaction/UserTransactionCaused by: java.lang.NoClassDefFoundError: javax/transaction/UserTr ...

  6. Linxu下 expect的实用实例_1

    案例 例1:从本机自动登录到远程机器192.168.1.200(端口是22,密码是:PASSWORD)登录到远程机器后做以下几个操作:1)useradd wangshibo2)mkdir /opt/t ...

  7. Sqoop操作集合

    1.在hive中建一个与mysql中一模一样的表 sqoop create-hive-table --connect jdbc:mysql://***.**.***.**:3306/数据库名称 --t ...

  8. codeforces 549F Yura and Developers(分治、启发式合并)

    codeforces 549F Yura and Developers 题意 给定一个数组,问有多少区间满足:去掉最大值之后,和是k的倍数. 题解 分治,对于一个区间,找出最大值之后,分成两个区间. ...

  9. MySQL面试宝典

    ==============================================# 参数==============================================auto ...

  10. 记录智能指针使用shared_ptr使用错误

    shared_ptr为智能指针,今天一次在使用shared_ptr时,错误的将其初始化方式写为shared_ptr<T> test = shared_ptr<T>(),随后导致 ...