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