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. spring 与mybatis 整合总结

    刚看完同学给我的代码,我忍不住爆粗.去TMD,写得像坨屎,恶心,乱七八糟,这让我怎么交差??一行代码注释都没有,还很自以为是的傲慢.“这都不懂?这就是Mybatis啊,有很多种方法实现.....” 操 ...

  2. 解决Spring框架下中文乱码的问题

    在使用了Spring框架下回发现很多表单交互的地方会发生乱码,而且写到数据库中也是乱码,这其实还是字符编码的问题,在我们还在用自己写的servlet的时候,直接在request和response加上字 ...

  3. 如何对iPhone进行屏幕录像

    如何对iPhone进行屏幕录像 录制时候的效果: 1. 打开QuickTime Player 2. 在文件中新建影片录制 3. 然后酱紫录制

  4. Redis 在Golang中使用遇到的坑

    1.从lua脚本传回到go那边的数字是string类型 2.hincrby 返回当前值的计算结果(即存放到redis中的值) 3.hset 一个不存在的key,返回什么呢?即设置失败返回什么错误?(会 ...

  5. August 24th 2017 Week 34th Thursday

    If you have choices, choose the best. If you have no choice, do the best. 如果有选择,那就选择最好的:如果没有选择,那就努力做 ...

  6. [EffectiveC++]item20:Prefer pass-by-reference-to-const to pass-by-value

  7. Windows 下安装Python包(Numpy)的错误:Unable to find vcvarsall.bat

    情景简介: Windows 环境下安装Python2.7的Numpy扩展包时提示:error: Unable to find vcvarsall.bat 经过不懈的Google/Bing,发现不仅安装 ...

  8. Linux常用软件安装

    1. 修改Linux的基本配置 1.修改主机名 vi /etc/sysconfig/network NETWORKING=yes HOSTNAME=server1.itcast.cn 2.修改ip地址 ...

  9. memcached的操作

    memcached是一个高性能的分布式内存对象缓存系统,用于动态web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库次数,从而提高动态.数据库驱动网站的速度.memcached基于 ...

  10. Codeforces Round #443 (Div. 2) 【A、B、C、D】

    Codeforces Round #443 (Div. 2) codeforces 879 A. Borya's Diagnosis[水题] #include<cstdio> #inclu ...