2019独角兽企业重金招聘Python工程师标准>>>
简陋的自定义组件滑动菜单效果实现(slides + slides)
最终效果如下:
简单的代码如下:
slide-tab-demo
{{slide.name}}
ts代码:
import { Component, ViewChild } from '@angular/core';
import { IonicPage, NavController, NavParams, Slides, Tabs } from 'ionic-angular';
@Component({
selector: 'page-slide-tab-demo',
templateUrl: 'slide-tab-demo.html',
})
export class SlideTabDemoPage {
@ViewChild("slidesRef")
slidesRef: Slides;
@ViewChild("tabsRef")
tabsRef: Tabs;
slides: any[] = [];
currentTabId = "tab1";
tabs: any[] = [];
navSelectedIndex = 0;
constructor(
public navCtrl: NavController,
public alert: Alert,
public navParams: NavParams
) {
this.slides = [{
name: '头条新闻'
}, {
name: '娱乐新闻'
},
{
name: '体育新闻'
}];
this.tabs = [{
_name: "头条",
num: 99
}, {
_name: "娱乐",
num: 0
}, {
_name: "热点",
num: 0
}, {
_name: "体育",
num: 4
}, {
_name: "财经",
num: 0
}, {
_name: "汽车",
num: 0
}, {
_name: "时尚",
num: 0
}];
}
slideClick(slideIndex) {
this.slidesRef.slideTo(slideIndex);
}
slideChanged($event) {
let currentIndex = this.slidesRef.getActiveIndex();
// this.alert.showAlert('sss');
this.navSelectedIndex = currentIndex;
}
}
简陋版slides+slides总结:能应付一般业务需求不繁琐的页面显示,但体验不好
一:滚动条问题,由于ion-slides的高度是以子页面ion-slide的高度为最终同一高度,当页面间高度不一致的时候,会导致高度矮的页面出现一大段空白背景,如果业务场景需要slide上拉刷新的时候,就要把空白背景拉完才会触发刷新效果。
解决办法:通过自定义指令获取屏幕高度减去上下tab栏来固定ion-slides的高度,但这时候会出现双滚动条,content一个,slides一个可能会出现其他的坑。
二:首页点击需要跳到指定的页面不好控制,在开发过程中,会出现点击滑动失效的问题,原因不明。
ionic2-super-tabs插件的使用
既然官方不提供,肯定有各路大神提供牛逼的组件,这个组件封装涵盖了angular的大部分核心思想及ionic页面生命周期,大神都说能写出来这个,其他组件随便封装。
ionic2-super-tabs introduction
基本使用上边都有说明,简单说一下
1、哪里用到super-tabs,就要在对应的module下引用
SuperTabsModule.forRoot()
2、页面充分用到懒加载[root]="xxPage",这里的Page就无需再次在根模块declarations、entryComponents、exports再次声明,直接在ts里xxpage : string = 'XXPage',字符串导入即可
3、进入子页面都会默认把前后一个页面同时渲染,有点类似ngIf(如6个子页面,进入第一个页面会渲染第一第二个页面,进入第二个页面会渲染第二第三个页面),所以如果请求数据太多要注重优化
4、父子页面的继承,只有第一次进入页面this的指向才是父页面,其余的操作都是指向每一个子页面,下面坑继续说
ionic2-super-tabs插件的注意地方
目录结构 业务场景(三个super-tabs同时存在task页面上)
由于一开始做这种需求是通过文首用的slides+slides的方法,很多都是通过this去全局控制每一个页面的状态,类型等,这个时候的this是非常好用的。但是用了super-tabs这个组件后this就失去了原来的光环。
原因剖析:super-tabs采用的是子页面加载,尽管这很好的解决首页跳转页面的问题,但随即而来的继承会导致this失效,每个task.ts除了第一次渲染this是指向TaskPage外,其余的任何操作都是指向当前的子页面,所以TaskPage的生命周期里面的操作也会到每个子页面上操作,这样就会重复做相同的事情。
解决办法:在ionViewDidLoad完成第一次加载所需的接口,在每个子页面都重写一个ionViewDidLoad,ionViewWillEnter周期覆盖父类的声明周期,这样就很好的规避一样操作重复做,其余的功能性操作如点击刷新列表等写在ionViewDidEnter,最好写在每个子页面。父类private的属性和方法,子类也能继承
task.html
task.ts (三个生命周期,大量运用到eventproxy神器)
注: this.navCtrl.getActiveChildNavs()用于获取是否有子类,无则undefined
self.navCtrl.getActiveChildNav().getActiveTab().getViews();获取子页面实例对象ViewController
ionViewDidLoad() {
let self = this;
let instance;
/*tslint:disable*/
console.log('task----load')
/*tslint:enable*/
//详情页返回删除数据
// 监听详情完成操作事件
// 如果要根据详情操作动态删除记录,详情操作结束派发事件‘finish_operate_in_details’
try {
window['epInstance'].unbind('finish_operate_in_details').bind('finish_operate_in_details', (option) => {
// 监听从详情进入任务父类页面
window['epInstance'].unbind('main_task_page_didenter').bind('main_task_page_didenter', (data) => {
// 获取子页面实例对象
let views = self.navCtrl.getActiveChildNav().getActiveTab().getViews();
if (views && views[0]) {
instance = views[0]['instance'];
}
let taskData = instance.taskArrTemp[option.segment][option.saveStatu] || [];
window['epInstance']['emit']('refresh_task_node_count', option.segment);
// 动态删除任务记录
taskData.forEach((item, index) => {
if (item.id === option.taskId || item.taskId === option.taskId) {
taskData.splice(index, 1);
}
});
});
});
} catch (e) {
}
// 叫我刷新我就刷新
try {
window['epInstance'].unbind('refresh_main_task_page').bind('refresh_main_task_page', (data) => {
let childInst = this.getChildPageInstnce();
if (childInst) {
childInst.selectInterface(false);
}
});
//刷新节点数量
window['epInstance'].unbind('refresh_task_node_count').bind('refresh_task_node_count', (segment) => {
this.getAppNodeTypeCount(segment);
});
} catch (e) {
/*tslint:disable*/
/*tslint:enable*/
}
}
ionViewWillEnter() {
//今日提醒
this._todayTask = this.global.getValue('todayTask');
// 详情页页面离开生命周期(ionViewDidLeave)派发leave_from_details事件。配合finish_operate_in_details事件控制动态删除记录
window['epInstance'].unbind('leave_from_details').bind('leave_from_details', (data) => {
window['epInstance']['emit']('main_task_page_didenter', null);
});
// 由于pageTaskItem已经继承了eventproxy实例,在pageTask页面再次继承该实例会被pageTaskItem的实例覆盖,所以要在全局定义变量
window['epInstance'].unbind('toggle_call_panel').bind('toggle_call_panel', (data) => {
if (data) {
this.toggleCallPanel = true;
Object.assign(this.taskPhone, data);
} else {
this.toggleCallPanel = false;
}
});
// 导航
window['epInstance'].unbind('toggle_nav_panel').bind('toggle_nav_panel', (data) => {
if (data) {
this.toggleNavPanel = true;
Object.assign(this.taskNav, data);
} else {
this.toggleNavPanel = false;
}
});
let activePages = this.navCtrl.getActiveChildNavs();
// 控制子类不要重复执行代码
if (this.global.getValue('segment') && activePages && activePages.length) {
let intervalTime = 10;
// 首次进入渲染较慢,延迟跳转,临时使用解决方案
// https://github.com/ionic-team/ionic/issues/12401 等待ionic-angular版本更新解决问题
if (this.firstEntry) {
//首次进入控制
intervalTime = 400;
}
// 外面定时器是保证先渲染好页面再转换任务状态,渲染新的supertabs
setTimeout(() => {
this.segment = this.global.getValue('segment');
this._tabIndex = this.global.getValue('tabIndex');
// 这里的定时器是因为ngIf销毁到生成新的supertabs慢,导致滑动会寻找销毁的tabs,从而报错
setTimeout(() => {
if (this.superTabs) {
this.superTabs.slideTo(this._tabIndex);
}
}, intervalTime)
this.global.remove('segment');
this.global.remove('tabIndex');
}, intervalTime);
}
this.firstEntry = false;
// 清空搜索筛选内容
window['search_input_content'] = '';
window['search_input_screen'] = '';
window['search_input_statu'] = 'all';
window['search_input_time'] = '';
}
ionViewDidEnter() {
// 子类才调用
let activePages = this.navCtrl.getActiveChildNavs();
if (!activePages || (activePages && !activePages.length)) {
window['epInstance']['emit']('refresh_task_node_count');
}
}
/**
* 获取子页面实例
*/
getChildPageInstnce() {
let instance;
let childNav = this.navCtrl.getActiveChildNav();
if (!childNav || (childNav && !childNav.getActiveTab)) {
return;
}
let views = childNav.getActiveTab().getViews();
if (views && views[0]) {
instance = views[0]['instance'];
}
return instance;
}
all-task.ts (一个子页面做覆盖父类的该周期)
ionViewDidLoad() {
}
ionViewWillEnter() {
this.saveStatu = 'all'
this.queryStatu = '';
this.requestData(this.newTask, false, '');
}
以上是最大的一个坑,下面是项目需求对组件的扩展
一、上边tab栏文字输入有长度要求,当超过长度会出现显示异常解决方案:
当最终确定长度手动渲染tab长度及总长度
参考文章:
ionic3之组件封装篇