Люди знают, что в последнее время я безумно влюблен в Ionic Framework , но я столкнулся с проблемой, с которой у меня возникли трудности. Я думал, что буду писать в блоге о проблеме и продемонстрирую решение, которое сработало для меня. Чтобы быть ясным, я думаю, что мое решение, вероятно, неправильно . Это работает, но это просто не чувствовать себя хорошо. Я специально делюсь этой записью в блоге, чтобы начать обсуждение и получить отзывы. По маловероятной вероятности, что то, что я показываю, является лучшим решением … хм … да … Я планировал это. Я великолепен.
Эта проблема
Итак, начнем с обсуждения проблемы. Учитывая типичное приложение Ionic, ваш Angular-код будет иметь метод .run, который прослушивает событие готовности ionicPlatform. Вот пример из «базового» начального приложения ( https://github.com/driftyco/ionic-app-base/blob/master/www/js/app.js ):
// Ionic Starter App
// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
angular.module('starter', ['ionic'])
.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if(window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if(window.StatusBar) {
// Set the statusbar to use the default style, tweak this to
// remove the status bar on iOS or change it to use white instead of dark colors.
StatusBar.styleDefault();
}
});
})
Событие ionicPlatform.ready вызывается, когда происходит событие устройства Cready в Cordova. Когда запускается на рабочем столе, он запускается в окне window.load. Хорошо, так что, на мой взгляд, я бы поместил код, который обычно находится в блоке document.ready. Все идет нормально.
Теперь давайте представим, что вы хотите использовать плагин, возможно плагин Device. Представьте, что вы хотите просто скопировать значение в $ scope, чтобы вы могли отобразить его в виде. Если этот контроллер / представление является первым представлением в вашем приложении, вы в конечном итоге получите состояние гонки. Angular будет отображать ваш вид и запускать ionicPlatform. Уже асинхронно. Это не ошибка, конечно, но это поднимает вопрос. Если вы хотите использовать функции плагина Cordova, и ваше приложение сразу же от него зависит , как вы справитесь с этим?
Одним из способов было бы удалить ng-app из DOM и самостоятельно загрузить Angular. Я сделал это … однажды, и я вижу, как это имеет смысл. Но я не хотел использовать это решение на этот раз, так как я хотел продолжать использовать ionicPlatform.ready. Я предположил (и могу ошибаться!), Что не могу сохранить это и удалить загрузчик ng-app.
Поэтому я добавил промежуточное представление к своему приложению. Простая целевая страница. Я изменил stateProvider, чтобы добавить новое состояние, а затем сделал его по умолчанию. В моем ionicPlatform.ready я использую сервис определения местоположения, чтобы перейти в предыдущее состояние по умолчанию.
.run(function($ionicPlatform,$location,$rootScope) {
$ionicPlatform.ready(function() {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if(window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if(window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleDefault();
}
$location.path('/tab/dash');
$rootScope.$apply();
});
})
Казалось, это сработало. Мой код контроллера, который запускается для представлений после этого, смог использовать плагины Cordova очень хорошо. Как насчет реального примера?
Демо
Одной из последних функций, появившихся в Ionic, являются вкладки в полосатом стиле . Это пользовательский интерфейс в стиле Android, и он будет автоматически применяться к приложениям, работающим на Android. Разница немного тонкая, когда вкладки находятся внизу:
Но при перемещении наверх с помощью tabs-top, это немного более драматично.
Ладно, круто. Но мне было интересно — как я могу получить вкладки сверху только для Android? Хотя я не из тех людей, которые считают, что элементы пользовательского интерфейса должны быть в определенной позиции на iOS по сравнению с Android, мне было любопытно, как бы я справился с этим программно.
Зная, что проверять плагин Device было тривиально, и теперь у меня есть возможность отложить просмотр до загрузки моих плагинов, и я решил использовать описанный выше подход, чтобы обеспечить доступ к платформе до загрузки этого конкретного представления.
Вот файл app.js, который я использовал, модифицированный из начального шаблона вкладок.
// Ionic Starter App
// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js
angular.module('starter', ['ionic', 'starter.controllers', 'starter.services'])
.run(function($ionicPlatform,$location,$rootScope) {
$ionicPlatform.ready(function() {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if(window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if(window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleDefault();
}
$location.path('/tab/dash');
$rootScope.$apply();
});
})
.config(function($stateProvider, $urlRouterProvider) {
// Ionic uses AngularUI Router which uses the concept of states
// Learn more here: https://github.com/angular-ui/ui-router
// Set up the various states which the app can be in.
// Each state's controller can be found in controllers.js
$stateProvider
// setup an abstract state for the tabs directive
.state('home', {
url:"/home",
templateUrl:'templates/loading.html',
controller:'HomeCtrl'
})
.state('tab', {
url: "/tab",
abstract: true,
templateUrl: function() {
if(window.device.platform.toLowerCase().indexOf("android") >= 0) {
return "templates/tabs_android.html";
} else {
return "templates/tabs.html";
}
},
})
// Each tab has its own nav history stack:
.state('tab.dash', {
url: '/dash',
views: {
'tab-dash': {
templateUrl: 'templates/tab-dash.html',
controller: 'DashCtrl'
}
}
})
.state('tab.friends', {
url: '/friends',
views: {
'tab-friends': {
templateUrl: 'templates/tab-friends.html',
controller: 'FriendsCtrl'
}
}
})
.state('tab.friend-detail', {
url: '/friend/:friendId',
views: {
'tab-friends': {
templateUrl: 'templates/friend-detail.html',
controller: 'FriendDetailCtrl'
}
}
})
.state('tab.account', {
url: '/account',
views: {
'tab-account': {
templateUrl: 'templates/tab-account.html',
controller: 'AccountCtrl'
}
}
});
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/home');
});
Вы можете увидеть, где я использую механизм location.path после того, как произошло событие ionicPlatform.ready. Вы также можете увидеть, где я нюхаю платформу устройства, чтобы определить, какой шаблон запустить. tabs_android.html точно такой же, как tabs.html, но с примененным классом tabs-top (*). Самым большим недостатком здесь является то, что приложение будет иметь ошибку при запуске на рабочем столе. Этого можно избежать, прослушивая отсутствие window.device и просто установив для него значение по умолчанию:window.device = {platform : "ios"};
Итак, это все. Как вы думаете? Я должен представить, что есть более хороший способ справиться с этим. Может быть, я ленивый, но я хочу использовать директивы Ionic и UX вместе с плагинами Cordova, и мне не нужно использовать такой неуклюжий обходной путь, как этот.
* Быстрая сноска. Я заметил, что если я попытаюсь добавить tabs-top в директиву ion-tabs, это никогда не сработает. Например, это то, что я попробовал в первую очередь: <ion-tabs ng-class="{'tabs-top':settings.isAndroid}">я использовал код в моем контроллере, который всегда устанавливал его в true (я еще не беспокоился о плагине устройства), и он фактически никогда не обновлял представление. Как будто область видимости контроллера не может изменить представление по какой-то странной причине.

