Ionic3项目实践记录
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. 父子页面通信
主要是通过NavController和NavParams来实现。
父向子直接通过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项目实践记录的更多相关文章
- 9-2、大型项目的接口自动化实践记录----递归判断两个json串是否相等
1.已知json串构成的情况下判断 先构造一下场景,假设已经把各个数据都移除掉不对比的字段 图1 预期.实际结果,复杂接口返回多层嵌套json时,同下 图2 预期.实际结果值为:{child_json ...
- 9-1、大型项目的接口自动化实践记录----数据库结果、JSON对比
上一篇写了如何从DB获取预期.实际结果,这一篇分别对不同情况说下怎么进行对比. PS:这部分在JSON对比中也适用. 1.结果只有一张表,只有一条数据 数据格式:因为返回的是dicts_list的格式 ...
- 8、大型项目的接口自动化实践记录----DB分别获取预期结果、实际结果
上一篇实现数据分离升级版--从DB获取数据,以及对应的请求实现,作为一个case,还缺少了预期结果与实际结果的获取及对比.因为前面的文章已经说过接口返回值的获取及对比,所以这篇不说这块了,这篇说一下D ...
- 3、大型项目的接口自动化实践记录----开放API练习
开始做实际项目前,先拿个网上的简单API练下手 一.API说明: 接口信息 接口名:京东获取单个商品价格 地址:http://p.3.cn/prices/mgets 入参:skuids=J_商品ID& ...
- 2、大型项目的接口自动化实践记录--接口测试简介及RequestsLibrary关键字简介
1.接口测试简介 1)先简单介绍下接口测试,那么什么是接口测试呢? 百科的回答:接口测试是测试系统组件间接口的一种测试.接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点. 看起来有 ...
- 1、大型项目的接口自动化实践记录--robotframework环境搭建
因为人力.团队技术问题,选用robotframework来做自动化,首先说下环境搭建 齐涛道长的入门教程非常棒:http://blog.csdn.net/tulituqi/article/detail ...
- Hangfire项目实践分享
Hangfire项目实践分享 目录 Hangfire项目实践分享 目录 什么是Hangfire Hangfire基础 基于队列的任务处理(Fire-and-forget jobs) 延迟任务执行(De ...
- Hangfire项目实践
Hangfire项目实践分享 Hangfire项目实践分享 目录 Hangfire项目实践分享 目录 什么是Hangfire Hangfire基础 基于队列的任务处理(Fire-and-forget ...
- MVC项目实践,在三层架构下实现SportsStore-01,EF Code First建模、DAL层等
SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管 ...
随机推荐
- 关于UNITY3D的各种各样。
作为一个老C++程序员,在接触了UNITY3D之后,除了玩C#还得玩JAVA和OBJECTIVE-C. 1年多的经验证明,UNITY3D游戏项目,如果打算做多平台,项目组里必须得有一个会多语言的万金油 ...
- GOOGLE高级搜索技巧
前记: 我是完整的看完了.内容有点乱啊,自己没有时间整理,先放在自己的印象笔记里了.... 二,GOOGLE特色 GOOGLE支持多达132种语言,包括简体中文和繁体中文: GOOGLE网站只提 ...
- java笔记--String类格式化当天日期转换符文档
String类格式化当天日期 --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3877389.html "谢谢-- 转换符:% ...
- [翻译] HTKDynamicResizingCell
HTKDynamicResizingCell https://github.com/henrytkirk/HTKDynamicResizingCell Subclassed UITableView/U ...
- Google官方教程之Selling In-app Products
1.原文链接[需FQ]:http://developer.android.com/training/in-app-billing/index.html 2.平时对于英文文档都是大概读一下,现在翻译文章 ...
- Windows Server 2012 AD域管理创建
前言 关于AD域管理及其权限划分概论: 1. AD域源于微软,适用于windows,为企业集中化管理和信息安全提供强力保障. 2. 提供域中文件夹共享,但同时又对不同用户有不用的权限. 3.通过对设备 ...
- Shortest Paths
最短路径 APIs 带权有向图中的最短路径,这节讨论从源点(s)到图中其它点的最短路径(single source). Weighted Directed Edge API 需要新的数据类型来表示带权 ...
- Python文件基础操作(IO入门1)
转载请标明出处: http://www.cnblogs.com/why168888/p/6422270.html 本文出自:[Edwin博客园] Python文件基础操作(IO入门1) 1. pyth ...
- 安装Jdk,tomcat【转载】
一.下载安装对应的jdk,并配置Java环境. 官网下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk-6u26-dow ...
- MySQL 触发器-更新字段时,status列会加一
需求:当更新列中的字段时,列中的status字段,就会+1 表结构 CREATE TABLE `test_1` ( `id` int(11) DEFAULT NULL, `name` varchar( ...