(頁面滑動)ionic2-super-tabs插件的使用及注意地方

簡陋的自定義組件滑動菜單效果實現(slides + slides)

最終效果以下:javascript

slides+slides實現菜單滑動

簡單的代碼以下:html

<ion-header>
  <ion-navbar>
    <ion-title>slide-tab-demo</ion-title>
  </ion-navbar>
<div>
  <task-slide (slideClick)="slideClick($event)" [slides]="tabs" [selectedIndex]="navSelectedIndex"  [taskType]="segment" [pageNumber]="4"></task-slide>
</div>
</ion-header>
<div style="height: 100%;;background-color:#999">
  <ion-slides #slidesRef (ionSlideDidChange)="slideChanged($event)">
    <ion-slide *ngFor="let slide of slides; let i = index;">
      <div class="list has-header" id="{{i}}">
        <ion-label>{{slide.name}}</ion-label>
      </div>
    </ion-slide>
  </ion-slides>
</div>

ts代碼:java

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總結:能應付通常業務需求不繁瑣的頁面顯示,但體驗很差node

一:滾動條問題,因爲ion-slides的高度是以子頁面ion-slide的高度爲最終同一高度,當頁面間高度不一致的時候,會致使高度矮的頁面出現一大段空白背景,若是業務場景須要slide上拉刷新的時候,就要把空白背景拉完纔會觸發刷新效果。git

解決辦法:經過自定義指令獲取屏幕高度減去上下tab欄來固定ion-slides的高度,但這時候會出現雙滾動條,content一個,slides一個可能會出現其餘的坑。github

二:首頁點擊須要跳到指定的頁面很差控制,在開發過程當中,會出現點擊滑動失效的問題,緣由不明。ionic

 

ionic2-super-tabs插件的使用

既然官方不提供,確定有各路大神提供牛逼的組件,這個組件封裝涵蓋了angular的大部分核心思想及ionic頁面生命週期,大神都說能寫出來這個,其餘組件隨便封裝。ide

ionic2-super-tabs introduction優化

基本使用上邊都有說明,簡單說一下this

一、哪裏用到super-tabs,就要在對應的module下引用

SuperTabsModule.forRoot()

二、頁面充分用到懶加載[root]="xxPage",這裏的Page就無需再次在根模塊declarations、entryComponents、exports再次聲明,直接在ts裏xxpage : string = 'XXPage',字符串導入便可

三、進入子頁面都會默認把先後一個頁面同時渲染,有點相似ngIf(如6個子頁面,進入第一個頁面會渲染第一第二個頁面,進入第二個頁面會渲染第二第三個頁面),因此若是請求數據太多要注重優化

四、父子頁面的繼承,只有第一次進入頁面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

<super-tabs id="taskTabs" #SuperTabs *ngIf="segment === 'newTask'" [config]="{ sideMenu: 'left' }" scrollTabs toolbarColor="orange"
        toolbarBackground="white" indicatorColor="orange" badgeColor="yellow" (tabSelect)="onTabSelect($event)">
        <super-tab [swipeBackEnabled]="false" [root]="waitAcceptPage" title="待受理({{newTaskCountObj.distributionWaitAccept}})" status="waitAcceptPage"></super-tab>
        <super-tab [root]="waitAppointmentPage" title="待預定({{newTaskCountObj.waitAppointment}})" status="waitAppointmentPage"></super-tab>
        <super-tab [root]="waitPickupPage" title="待提貨({{newTaskCountObj.waitPickUp}})" status="waitPickupPage"></super-tab>
        <super-tab [root]="waitSignPage" title="待簽收({{newTaskCountObj.waitSign}})" status="waitSignPage"></super-tab>
        <super-tab [root]="hadSignPage" title="已簽收({{newTaskCountObj.doSign}})" status="hadSignPage"></super-tab>
        <super-tab [root]="cancelledPage" title="已取消({{newTaskCountObj.invalid}})" status="cancelledPage"></super-tab>
        <super-tab [root]="allTaskPage" title="所有({{newTaskCountObj.all}})" status="allTaskPage"></super-tab>
</super-tabs>

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, '');
}

以上是最大的一個坑,下面是項目需求對組件的擴展

1、上邊tab欄文字輸入有長度要求,當超過長度會出現顯示異常解決方案:

當最終肯定長度手動渲染tab長度及總長度

 

 

參考文章:

ionic3之組件封裝篇

相關文章
相關標籤/搜索