<ion-tabs class="tabs-icon-top"> <ion-tab href="/home" icon="ion-home" title="首頁"></ion-tab> <ion-tab href="/order" icon="ion-compose" title="訂位"></ion-tab> </ion-tabs>此外,<ion-nav-bar>等指令也同樣重複出現。為了讓程式碼共用,必須採用「共用states」的方式。
共用states
UI-Router可定義abstract state-也就是操作過程中不能直接瀏覽的頁面-讓多個states共用;而abstract state是parent state;其他共用abstract state的頁面則為child states。因此,4.1的頁籤範例修改的部分如下圖所示。
圖1.頁籤頁面的內容定義為abstract state(如tab state),便可讓其他state共用。 |
- 加入新的abstract state,該state和一般state不同,必須加入屬性"abstract : true"例如:
...[略]... .state('tab',{ url: '/tab', abstract: true, templateUrl: 'templates/tabs.html' }) ...[略]...
- 修改其他要共用abstract state的頁面定義,加入views屬性,並給予名稱:
...[略]... .state('tab.home',{ url: '/home', views: { 'tab-home': { templateUrl: 'templates/home.html', controller: 'homeCtrl' } } }) ...[略]...
和原先state定義不同除了名稱(由home改為tab.home,tab為abstract state名稱)之外,還加入了views屬性,並給予名稱(例如tab-home),將頁面檔案、controller的設定放在其中。views的名稱相當重要,會出現在parent state的頁面檔的<ion-nav-view>之name屬性,以便將此名稱所代表的子頁面,帶入parent state中。 - 將頁籤共用的部份獨立出來另存新檔,注意每個<ion-tab></ion-tab>內都要加入<ion-nav-view>指令,並設定其name屬性為對應子頁面views屬性所定義的名稱,例如:
此處'tab-home', 'tab-order'便分別定義於兩個state的views屬性內。而第3行第6行href的網址須加上parent state的url,例如/home變為 /tabs/home。此乃因為各頁面的url定義雖然不變,但state位階變為abstract state的children,故各頁面完整的url必須加上parent state的url。<ion-tabs> <ion-tab href="‘/tab/home’"> <ion-nav-view name="‘tab-home’"> </ion-nav-view> </ion-tab> <ion-tab href="‘/tab/order’"> <ion-nav-view name="‘tab-order’"> </ion-nav-view> </ion-tab> </ion-tabs> - 其他如<ion-nav-bar>指令可直接移至index.html,做為app本身layout的一部分。例如:
<ion-nav-bar> <ion-nav-back-button> </ion-nav-back-button> </ion-nav-bar> <ion-nav-view> </ion-nav-view>
天氣app(非線上版)
圖2. 天氣App介面 |
圖3.專案結構 |
檔案內容
app.js關於config設定的部份如下:angular.module('starter', ['ionic', 'starter.controllers']) .config(function ($stateProvider, $urlRouterProvider, $ionicConfigProvider) { $ionicConfigProvider.tabs.position('bottom'); $urlRouterProvider.otherwise('/tab/home'); $stateProvider .state('tab', { url: '/tab', abstract: true, templateUrl: 'templates/tabs.html' }) .state('tab.home', { url: '/home', views: { 'tab-home': { templateUrl: 'templates/home.html', controller: 'homeCtrl' } } }) .state('tab.settings', { url: '/settings', views: { 'tab-settings': { templateUrl: 'templates/settings.html', controller: 'settingsCtrl' } } }) .state('weather', { url: '/tab/home/:id', templateUrl: 'templates/weather.html', controller: 'weatherCtrl' }); })
- 第2-3行:為了讓頁籤在不同行動平台上都出現在頁面下方,使用$ionicConfigProvider服務,以.tab.position('bottom')設定頁籤固定於下方(Android預設位置在頁面上方)。
- 第6-9行:共用的parent state定義,注意第8行"abstract:true"為必要屬性設定。
- 第11-19行:圖2左邊頁面的定義。注意第14行views名稱設為'tab-home',此名稱要用於第9行tabs.html內。
- 第20-28行:圖2中間頁面的定義。第21行views名稱設為'tab-settings',此名稱必須用於第9行parent state的html檔內。
- 第30行:最後一個'weather' state設定與前幾個均不相同,因為weather並未與其他頁面共用'tab' state。此外,由於weather的用途是顯示某城市的天氣概況,城市序號會由'tab.home' state傳來,因此url必須設定為'/tab/home/:id',而非'/home/:id',因為tab.home的完整url須結合parent state的url,而成為'tab/home'。
templates/tabs.html檔案內容如下:
<ion-tabs class="tabs-icon-top"> <ion-tab title="天氣" icon="ion-home" href="#/tab/home"> <ion-nav-view name="tab-home"></ion-nav-view> </ion-tab> <ion-tab title="設定" icon="ion-settings" href="#/tab/settings"> <ion-nav-view name="tab-settings"></ion-nav-view> </ion-tab> </ion-tabs>
- 第2, 5行:href設定值必須包含parent state的部分-'#/tab'。
- 第3, 6行:每個<ion-tab>各加入自己的<ion-nav-view>,name屬性值必須與state設定的views名稱相同。
starter.controllers定義於js/controllers.js,檔案內容如下:
angular.module('starter.controllers',[]) .controller('homeCtrl',function($scope,$location){ $scope.citys = citys; $scope.showWeather = function(index){ $location.path('/tab/home/'+index); } }) .controller('settingsCtrl',function($scope){ $scope.citys = citys; }) .controller('weatherCtrl',function($scope,$stateParams){ $scope.weather = weather[$stateParams.id]; $scope.img_base_url = image_base_url; }) var citys = [ {name: "台北", q: "Taipei", on: true}, {name: "台中", q: "Taichung", on: true}, {name: "台南", q: "Tainan", on: true}, {name: "高雄", q: "Kaohsiung", on: true}, {name: "花蓮", q: "Hualian", on: true}, ] var image_base_url = "http://openweathermap.org/img/w/"; // open weather api icon var weather = [ {"coord": {"lon": 121.53, "lat": 25.05}, "sys": {"message": 0.0418, "country": "TW","sunrise": 1429565168, "sunset": 1429611544}, "weather": [{"id": 500, "main": "Rain", "description": "light rain", "icon": "10n"}], "base": "stations", "main": {"temp": 292.18, "temp_min": 292.18, "temp_max": 292.18, "pressure": 1022.92, "sea_level": 1031.39, "grnd_level": 1022.92, "humidity": 100}, "wind": {"speed": 3.75, "deg": 41.0005}, "clouds": {"all": 92}, "rain": {"3h": 0.13}, "dt": 1429625933, "id": 1668341, "name": "Taipei", "cod": 200}, //...略... ]
- 第4-6行:定義showWeather()事件處理器,給頁面使用。下一個檔案home.html便會說明因為捨棄之前用超連結<a href="指定url">的方式,改用ng-click,所以提供此事件處理器做轉址動作。Ionic/AngularJS之$location提供轉址服務,故第2行函式定義處加上$location參數,第5行再呼叫$location.path()進行轉址。
- 第11-14行:和Hybrid Apps開發系列之4.3:多頁面App程式 (清單/細節瀏覽)範例相同,天氣概況頁面的城市參數也是透過$stateParams傳遞進來,$stateParams.id之'id'係因.config裡weather state定義了"'tab/home/:id"而得。
- 第16-22:自定資料陣列。on屬性係用來記錄settings頁面各項目的開關(toggle)狀態。
- 第24-37行:是從open weather api取得的台北市資料,其他城市資料則省略。
首頁templates/home.html檔案內容如下:
<ion-view title="目前天氣"> <ion-content> <ion-list class="list"> <ion-item class="item item-icon-left" ng-repeat="city in citys" ng-click="showWeather($index)" ng-show="city.on"> <i class="icon ion-ios-home-outline"></i> {{city.name}} </ion-item> </ion-list> </ion-content> </ion-view>
- 第4-9行:單一項目。第3行先使用<ion-list class="item">定義清單區塊,區塊內再用<ion-item class="item">定義每一個項目,如下所示:
<ion-list class="item"> <ion-item class="item"></ion-item> <ion-item class="item"></ion-item> ... </ion-list>
此處以ng-repeat套用controller端$scope所設定的資料模型陣列,帶出城市資料,ng-click則取代之前的超連結做法,提供設定點選事件處理的函式呼叫。$index同樣是ng-repeat進行的次數,由0算起,故可代表城市資料陣列的序號。ng-show運用城市資料的on屬性值,決定是否顯示該項目。on屬性質透過下面settings.html頁面進行變更。
<ion-view title="城市列表"> <ion-content> <ion-list> <ion-item class="item item-toggle" ng-repeat="city in citys"> {{city.name}} <label class="toggle toggle-assertive"> <input type="checkbox" ng-model="city.on"> <div class="track"> <div class="handle"></div> </div> </label> </ion-item> </ion-list> </ion-content> </ion-view>
- 第6-11行:開關(toggle)的CSS設定較為複雜,最外層以<label class="toggle">標示,僅跟著第7行設定input type為"checkbox",並以ng-model綁定controller端設定的變數;最後再以<div class="track">包住<div class="handle">顯示開關的外型。
天氣概況頁面templates/weather.html內容如下:
<ion-view title="天氣概況"> <ion-content> <div class="list card"> <div class="item"> <h2>City of {{weather.name}}</h2> </div> <div class="item item-avatar"> <img src="{{img_base_url+weather.weather[0].icon+'.png'}}"> <h2>{{weather.main['temp']-273.15 | number:1}}°C</h2> <h2>{{(weather.dt)*1000 | date:'yyyy-MM-dd HH:mm:ss'}}</h2> </div> <div class="item"> <div class="row"> <div class="col">濕度</div> <div class="col">{{weather.main.humidity}}%</div> </div> <div class="row"> <div class="col">風速</div> <div class="col">{{weather.wind.speed}}哩/秒</div> </div> </div> </div> </ion-content> </ion-view>
- 此頁面CSS格式是參考Ionic官網關於Card Images與 Gird兩部分的範例做成。open weather api回傳的資料則可參考http://openweathermap.org/weather-data#current。
index.html檔定義如下:
[...略...] <!-- your app's js --> <script src="js/app.js"></script> <script src="js/controllers.js"></script> <body ng-app="starter"> <ion-nav-bar> <ion-nav-back-button></ion-nav-back-button> </ion-nav-bar> <ion-nav-view> </ion-nav-view> </body> </html>
沒有留言:
張貼留言