Люди знают, что в последнее время я безумно влюблен в 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 (я еще не беспокоился о плагине устройства), и он фактически никогда не обновлял представление. Как будто область видимости контроллера не может изменить представление по какой-то странной причине.