Github: ДЕМО-КОД

Некоторое время назад блестящие ребята из @ Ionic выпустили компонент split-pane, обещавший сделать ионные приложения еще на шаг ближе к тому, чтобы они были по-настоящему отзывчивыми, вплоть до настольных компьютеров. Хотя их сообщение с объявлением о новом компоненте выглядело великолепно, все примеры, казалось, использовали новый компонент для отображения меню рядом с основным контентом вашего приложения. Хотя я уверен, что это будет популярный подход, я хотел использовать разделенную панель, чтобы помочь мне реализовать приложение в стиле мастер-детали, например это…

… И, похоже, не было никаких примеров, которые помогли бы начать работу с такого рода вещами. Так…

Начиная

Я создал пустой проект ionic 3, созданный с помощью ionic-cli. К этому я добавил 3 страницы (весь демонстрационный код см. На github):

  • Страница «Элементы», содержащая элементы нашего списка («основное представление»)
  • Страница «Элемент» для отображения отдельного элемента («подробное представление»)
  • Страница "заполнитель", чтобы "заполнить пробел" на рабочем столе, когда "элемент" не выбран.

Теперь, когда это работает, ключевая идея, о которой следует подумать, заключается в следующем:

  • На настольном компьютере вам понадобятся два ионных NavController, один для основного представления и один для подробного представления.
  • На мобильном вам понадобится только один ионный NavController, и вы захотите скрыть подробное представление

Так вот…

Итак, как мы это сделаем? Что ж, нам нужно:

  • Настройка CSS компонентов "разделенной панели" таким образом, чтобы представление подробностей было скрыто на мобильном устройстве.
  • Добавьте службу навигации Прокси, чтобы упростить работу с двумя контроллерами NavController.
  • Каким-то образом "пометьте" свои страницы как основные или подробные, чтобы мы могли указать в коде, с каким типом страницы мы имеем дело.
  • Добавьте в наше приложение компонент разделенной панели и слушайте, когда он активирован / деактивирован.
  • Подключите все вместе

1. Настройте стили компонентов с разделенной панелью (МЕНЬШЕ)

.split-pane-side:not(ion-menu) {
    display: initial;
}
.split-pane-main {
    display: none;
}
.split-pane-visible {
    .split-pane-main {
        display: block;
    }
}

2. Добавьте навигационную службу «Прокси».

import { Injectable } from '@angular/core';
import { Nav } from 'ionic-angular';
import { PlaceholderPage } from '../pages/placeholder/placeholder';
import { _DetailPage } from '../pages/_DetailPage';
@Injectable()
export class NavProxyService {
    _masterNav: Nav = null;
    get masterNav(): Nav {
        return this._masterNav;
    }
    set masterNav(value: Nav) {
        this._masterNav = value;
    }
    _detailNav: Nav = null;
    get detailNav(): Nav {
        return this._detailNav;
    }
    set detailNav(value: Nav) {
        this._detailNav = value;
    }
    _isOn: boolean = false;
    get isOn(): boolean {
        return this._isOn;
    }
    set isOn(value: boolean) {
        this._isOn = value;
    }
    pushDetail(page: any, params: any) {
        (this.isOn) ?
            this.detailNav.setRoot(page, params):
            this.masterNav.push(page, params);
    }
    pushMaster(page: any, params: any) {
        this.masterNav.push(page, params);
    }
    onSplitPaneChanged(isOn) {
        // set local 'isOn' flag...
        this.isOn = isOn;
        // if the nav controllers have been instantiated...
        if (this.masterNav && this.detailNav) {
            (isOn) ? this.activateSplitView() :
                     this.deactivateSplitView();
        }
    }
    activateSplitView() {
        let currentView = this.masterNav.getActive();
            if (currentView.component.prototype 
                instanceof _DetailPage) {
                // if the current view is a 'Detail' page...
                // - remove it from the 'master' nav stack...
                this.masterNav.pop();
                // - and add it to the 'detail' nav stack...
                this.detailNav.setRoot(
                    currentView.component, 
                    currentView.data);
            }
     }
    deactivateSplitView() {
        let detailView = this.detailNav.getActive();
        this.detailNav.setRoot(PlaceholderPage);
        if (detailView.component.prototype instanceof _DetailPage) {
            // if the current detail view is a 'Detail' page...
            // ...so, not the placeholder page:
            let index = this.masterNav.getViews().length;
            // add it to the master view...
            this.masterNav.insert(index, 
                detailView.component, 
                detailView.data);
        }
    }
}

Затем добавьте это в массив «провайдеров» вашего модуля angular:

...
import { 
    NavProxyService 
} from '../services/NavProxy.service';
...
@NgModule({
    ...
    providers: [
        ...
        NavProxyService,
        ...
    ]
})
export class AppModule { }

3. «Пометить» страницы как «основные» или «подробные».

Есть несколько способов добиться этого ... Я решил расширить компоненты ионной страницы двумя настраиваемыми абстрактными классами:

export abstract class _MasterPage { }
export abstract class _DetailPage { }

Затем главная страница, Элементы была расширена с помощью _MasterPage, а страница сведений - с помощью _DetailPage:

...
@IonicPage()
@Component({
    ...
})
export class ItemsPage extends _MasterPage { ... }
...
@IonicPage()
@Component({
    ...
})
export class ItemPage extends _DetailPage { ... }

Они используются нашим NavProxyService для определения того, с каким типом страницы он работает, и внутренне используются, чтобы решить, в какой NavController отправить страницу.

4. Добавьте в приложение компонент «разделенная панель» и узнайте, когда он будет активирован / деактивирован.

В /src/app/app.html мы собираемся добавить ion-split-pane компонент и два ion-nav компонента для обработки нашего основного и подробного стека навигации (обратите внимание на (ionChange=’…’) на ion-split-pane):

...
<ion-split-pane 
    (ionChange)="navProxy.onSplitPaneChanged($event._visible)">
    <ion-nav [root]="masterPage" 
             #masterNav>
    </ion-nav>
    <ion-nav [root]="detailPage" 
             #detailNav main> 
    </ion-nav>
</ion-split-pane>
...

5. Соедините все вместе.

Эта часть довольно проста, просто установите наш NavProxyService в /src/app/app.component.ts':

import { Component, ViewChild } from '@angular/core';
...
import { NavProxyService } from '../services/NavProxy.service';
import { ItemsPage } from '../pages/items/items';
import { PlaceholderPage } from '../pages/placeholder/placeholder';
@Component({
    ...
})
export class MyApp {
    // Grab References to our 2 NavControllers...
    @ViewChild('detailNav') detailNav: Nav;
    @ViewChild('masterNav') masterNav: Nav;
    ...
    constructor(
        ...
        private navProxy: NavProxyService) {
        platform.ready().then(() => {
            ...
            // Add our nav controllers to
            // the nav proxy service...
            navProxy.masterNav = this.masterNav;
            navProxy.detailNav = this.detailNav;
            // set initial pages for
            // our nav controllers...
            this.masterNav.setRoot(ItemsPage, 
                { detailNavCtrl: this.detailNav });
            this.detailNav.setRoot(PlaceholderPage);
        });
    }
}

… И измените /src/pages/items, чтобы использовать наш NavProxyService d при запросе страниц сведений:

...
import { NavProxyService } from '../../services/NavProxy.service';
import {_MasterPage, ItemPage } from '../';
@IonicPage()
@Component({
    ...
})
export class ItemsPage extends _MasterPage {
    constructor(public navCtrl: NavController,
                public navParams: NavParams,
                private navProxy: NavProxyService) {
        super();
    }
    onItemSelected(item) {
        // Rather than using:
        //     this.navCtrl.push(...)
        // Use our proxy:
        this.navProxy.pushDetail(ItemPage, item);
    }
}

Вот и все. Просто зажгите его из ionic serve, и вас уже не будет ...

Надеюсь, это поможет.

Демо-код: https://github.com/martinpritchardelevate/ionic-split-pane-demo