4 Ionic導航和核心組件--旅游應用


 

 

  簡介:在本節課中,我們將會通過一個虛構的旅游景點來構建一款功能完善的應用。本應用的核心特性是管理用戶的應用內導航。本節課的主要目的,是展現構建一個完整的應用的過程。

  無論是什么移動應用,最重要的功能之一都是讓用戶可以在應用內導航,首先需要設置應用導航必要的基礎部分,然后繼續使用Ionic用戶界面組件來構建新界面,所有組件協同工作,讓應用可以顯示天氣信息,游客的預訂信息以及附近的景點信息,應用還會使用一個簡單的幻燈片來做新手指引,這個在許多應用中我們都有見到。

  下面我們先來展示一下基本的 應用流程圖:

  

  下面進入開發環節:

  4.1 配置項目

  我們先來配置項目,基礎環境,我在第二節課的時候已經講過了,現在先來看看版本:

  

  我們先來創建一個空的項目,執行命令:

  

  安裝完成后進入文件夾:

  

  啟動服務:

  

  我們會看到這樣一個頁面:

  

  4.2 配置應用導航

  開始構建應用之前,我們來看下用戶可以訪問的視圖都有哪些~

  

  以上圖片展示的只是概覽,我們需要構建每個視圖,下面我們先來配置應用導航,然后再給每個視圖添加內容。Ionic支持第三方路由框架ui-router,它是導航的中央大腦,Ionic就是在ui-router基礎上開發的,所以不需要關心底層細節,除非要開發自定義的導航功能。

  現在,我們來理解一下導航和路由的概念。導航是指用戶在應用內部移動的動作,路由是指應用內部的過程,用於控制用戶導航時具體的行為。換句話來解釋,就是導航時用戶的行為,路由是應用響應用戶輸入的邏輯。

  我們的第一個任務是向應用的index.html文件添加一個Ionic導航組件,然后再聲明一個起始視圖。

  ionNavView和ionNavBar是Ionic的基礎組件,用於導航。ionNavView就像一個占位符,用於把不同的視圖內容載入應用,ionNavBar是標題欄,在用戶跳轉新視圖時自動更新。這兩個組件是一同工作的,不過如果你不想要頂部的導航欄,也可以單獨使用ionNavView。ionNavBar在應用的頂部,我們可以在這里放置當前視圖的標題,也可以放置按鈕,如果返回按鈕,在我們的應用中,會使用ionNavBackButton組件來實現一種返回方式。

  打開index.html文件,加入導航組件:

<!-- 把angular應用插入頁面 -->
<body ng-app="starter">
    <!-- 聲明ionNavBar,並且添加bar-positive類 -->
    <ion-nav-bar class="bar-positive">
        <!-- 聲明ionNavBackButton,如果有上一級視圖就會出現 -->
        <ion-nav-back-button class="button-clear">
            <!-- 用返回箭頭圖標來當做返回按鈕 -->
            <i class="icon ion-ios-arrow-left"></i> Back
        </ion-nav-back-button>
        <!-- 聲明ionNavView,這里會顯示每個視圖的內容 -->
    </ion-nav-bar>
    <ion-nav-view></ion-nav-view>
</body>

  我們現在運行代碼,會發現頁面上什么功能都沒有,這是因為我們還沒有聲明任何視圖。然后我們需要來聲明應用的一些列狀態,狀態是ui-router的一個概念,狀態對應應用當前需要顯示的視圖,其中會包括視圖對應的URL、視圖控制器的名字和視圖對應的模板。

  下面我們來聲明第一個狀態-->home狀態,打開www/js/app.js文件:

angular.module('starter', ['ionic'])
//添加新的config方法並注入$stateProvider
.config(function($stateProvider,$urlRouterProvider){
  //聲明第一個狀態對應的是主視圖
  $stateProvider.state('home', {
    //給狀態設置一個URL,可以用在錨點連接上
    url:'/home',
    //視圖激活時,讓這個狀態從指定的URL加載模板
    templateUrl:'view/home/home.html'
  });
  //聲明降級URL,如果應用找不到請求的狀態會跳轉到這里
  $urlRouterProvider.otherwise('/home');
})
.run(function($ionicPlatform) {...

  上面的代碼中,我們使用$stateProvider服務來聲明狀態,用$urlRouterProvider在請求無效的時候指定跳轉地址。otherwise()方法非常重要,因為它會在應用無法找到目標路由時發揮作用,比如王章的404錯誤。如果用戶試圖請求一個不存在的狀態,otherwise()方法會顯示主視圖,所以最好保證有otherwise()方法。

  我們在上面聲明了一個模板,但是沒有創建對應的文件,下面我們就來創建主視圖文件。創建新文件www/views/home/home.html文件並寫入如下代碼:

<ion-view view-title="旅游啦" hide-back-button="true">
</ion-view>

  現在運行代碼,我們可以看到這樣的頁面:

  

  注意hide-back-button屬性,它控制視圖是否可見返回按鈕。

  4.3 構建主視圖

  現在項目只有一個帶標題的空視圖,我們需要給視圖添加內容。這時,我們需要用到ionContent來創建內容容器,這是一個通用的內容封裝器,它有很多特性:根據設備調整內容區域的尺寸、和頭部底部協同合作、管理滾動。最常用的就是管理滾動。下面我們打開home.html文件,加入如下內容:

<ion-view view-title="旅游啦" hide-back-button="true">
    <!-- 顯示主視圖的內容 -->
    <ion-content>
    </ion-content>
</ion-view>

  現在有了內容容器了,我們需要向應用中添加一個基礎的列表組件,還是打開home.html文件,加入如下內容:

<ion-view view-title="旅游啦" hide-back-button="true">
    <!-- 顯示主視圖的內容 -->
    <ion-content>
        <!-- 給容器元素添加list類,從而指定它為列表容器 -->
        <div class="list">
            <!-- 給元素添加item類,從而創建一個列表元素,這里它會鏈接到其他視圖 -->
            <a href="#/reservation" class="item">預訂信息</a>
            <a href="#/weather" class="item">本地天氣</a>
            <a href="#/restaurants" class="item">附近餐館</a>
        </div>
    </ion-content>
</ion-view>

  現在頁面效果如下圖所示:

  

 

  現在,我們來給主視圖的列表項添加圖標,ionic自帶許多的圖標,它們被稱為ionicons。

  打開home.html文件,我們來給主視圖添加圖標:

<ion-view view-title="旅游啦" hide-back-button="true">
    <!-- 顯示主視圖的內容 -->
    <ion-content>
        <!-- 給容器元素添加list類,從而指定它為列表容器 -->
        <div class="list">
            <!-- 給元素添加item類,從而創建一個列表元素,這里它會鏈接到其他視圖,添加item-icon-left類來獲取我們想要的效果 -->
            <a href="#/reservation" class="item item-icon-left">
                <!-- 給i元素添加圖標類,就可以展示圖標了 -->
                <i class="icon ion-document-text"></i> 預訂信息
            </a>
            <a href="#/weather" class="item item-icon-left">
                <i class="icon ion-ios-partlysunny"></i> 本地天氣
            </a>
            <a href="#/places" class="item item-icon-left">
                <i class="icon ion-fork"></i> 附近景點
            </a>
        </div>
    </ion-content>
</ion-view>

  主視圖效果如下圖所示:

  

 

  4.4 使用控制器和模型來開發預訂視圖

  對於預訂視圖,由於我們需要加載用戶的數據並顯示出來,所以可以使用控制器來管理數據。下面我們先來創建一個新的控制器,創建文件www/views/reservation/reservation.js:

//引入angular模塊
angular.module('starter')
//聲明控制器的名字和函數,接受一個元素到列表並注入$scope中
.controller('ReservationController', function($scope){
    //把模型對象賦值給$scope
    $scope.reservation = {
        //設定停留日期
        checkin:new Date(),
        checkout:new Date(Date.now()+1000*60*60*24*7),
        //設置預訂需要的其他靜態值
        room:208,
        rate:121,
        wifi:'208wifi',
        wificode:'888888'
    };
});

  下面我們來構建一下預訂視圖,創建www/views/reservation/reservation.html文件:

<ion-view view-title="預訂信息">
    <ion-content>
        <!-- 使用列表組件包裹列表 -->
        <div class="list">
            <div class="item item-icon-left">
                <!-- 設置圖標,把數據綁定到模板中 -->
                <i class="icon ion-key"></i>
                房間號:{{reservation.room}}
            </div>
            <div class="item item-icon-left">
                <i class="icon ion-calendar"></i>
                入住時間:{{reservation.checkin | date:'mediumDate'}}
            </div>
            <div class="item item-icon-left">
                <i class="icon ion-calendar"></i>
                離開時間:{{reservation.checkout | date:'mediumDate'}}
            </div>
            <div class="item item-icon-left">
                <i class="icon ion-wifi"></i>
                WIFI:{{reservation.wifi}}
            </div>
            <div class="item item-icon-left">
                <i class="icon ion-wifi"></i>
                WIFICode:{{reservation.wificode}}
            </div>
            <div class="item item-icon-left">
                <i class="icon ion-pricetag"></i>
                單價:{{reservation.rate | currency}}/晚
            </div>
            <div class="item item-icon-left">
                <i class="icon ion-pricetags"></i>
                總價:{{reservation.rate * 7 | currency}}
            </div>
        </div>
    </ion-content>
</ion-view>

  現在,我們有了預訂視圖以及將數據顯示出來,剩下的只需要把這個視圖添加到應用的狀態管理器當中,打開app.js文件,接着主視圖添加以下代碼:

            //聲明預覽視圖的狀態
            .state('reservation', {
                //使用/reservation URL來標識這個狀態
                url: '/reservation',
                //聲明這個視圖用到的控制器的名稱
                controller: 'ReservationController',
                //聲明要加載的視圖文件
                templateUrl: 'views/reservation/reservation.html'
            });        

  然后,把reservation.js文件引入到index.html文件的</head>標簽前面。此時,我們的預訂視圖已經完成了,預覽效果如下圖:

  

  4.5 把數據加載到天氣視圖中

  現在我們來完成天氣視圖,天氣視圖的功能是從外部服務器載入天氣數據,所以我們先來配置控制器來加載外部天氣數據。我們需要使用到Angular提供的$http服務來從一個URL加載數據,把$http服務注入到控制器,訪問一個URL,然后處理HTTP請求的成功或者失敗的情況。首先我們先來創建一個新的控制器文件www/views/weather/weather.js:

//引用angular模塊
angular.module('starter')
//聲明控制器並注入$scope和$http服務
.controller('WeatherController', function($scope, $http){
    //聲明包含所有可能風向的數組
    var directions = ['北','東北','東','東南','南','西南','西','西北'];
    //發起HTTP請求來從給定的URL加載數據
    $http.get('http://ionic-in-action-api.herokuapp.com/weather')
    //處理響應成功的情況,並獲取返回天氣對象
    .success(function(weather){
        //把天氣數據賦值給$scope.weather模型
        $scope.weather=weather;
    })
    //在這里做錯誤處理
    .error(function(err){});
    //用來把角度值轉換成風向的方法
    $scope.getDirection = function(degree){
        if(degree > 338){
            degree = 360 - degree;
        }
        var index = Math.floor((degree+22)/45);
        return directions[index];
    };
});

  然后我們來給添加視圖添加一個模板,創建文件www/views/weather/weather.html:

<ion-view view-title="天氣情況">
    <!-- 用容器包裹內容 -->
    <ion-content>
        <div class="list">
            <!-- 添加列表元素,綁定天氣對象的數據 -->
            <div class="item">天氣:{{weather.weather[0].main}}</div>
            <div class="item">溫度:{{weather.main.temp}}&deg;</div>
            <div class="item">空氣濕度:{{weather.main.humidity}}%</div>
            <div class="item">最高氣溫:{{weather.main.temp_max}}&deg;</div>
            <div class="item">最低氣溫:{{weather.main.temp_min}}&deg;</div>
            <div class="item">
                <!-- 風向元素有兩個綁定數據,第二個會調用作用域中的第一個方法 -->
                風向:{{weather.wind.speed}}mph,{{getDirection(weather.wind.deg)}}
            </div>
        </div>
    </ion-content>
</ion-view>

  然后我們來聲明天氣視圖狀態,打開app.js文件,在預訂視圖下面添加如下代碼:

            //聲明天氣視圖狀態
            .state('weather',{
                //給聲明的狀態添加URL、控制器和模板值
                url:'/weather',
                controller:'WeatherController',
                templateUrl:'views/weather/weather.html'
            });        

  現在我們運行一下吧,預覽結果如下圖:

  

  此時當我們執行應用的時候,會發現視圖會有一個加載過程,頁面數據會出現一個短暫的空白時期,知道數據加載完畢,這樣的用戶體驗並不理想,所以我們需要加載一個載入指示器。但是在展示加載動畫的時候用戶無法操作應用,所以要考慮清楚是否要這樣做。現在我們先來實現一下如何加載動畫。

  加載組件有兩個方法:show()和hide()。我們需要在HTTP請求執行時顯示加載指示器,在響應返回后隱藏它。下面我們打開weather.js文件,做如下修改:

//引用angular模塊
angular.module('starter')
//聲明控制器並注入$scope和$http服務,把$ionicLoading服務注入控制器中
.controller('WeatherController', function($scope, $http, $ionicLoading){
    //聲明包含所有可能風向的數組
    var directions = ['北','東北','東','東南','南','西南','西','西北'];
    //在HTTP請求開始之前顯示加載組件
    $ionicLoading.show();
    //發起HTTP請求來從給定的URL加載數據
    $http.get('http://ionic-in-action-api.herokuapp.com/weather')
    //處理響應成功的情況,並獲取返回天氣對象
    .success(function(weather){
        //把天氣數據賦值給$scope.weather模型
        $scope.weather=weather;
        //如果響應成功,隱藏加載組件
        $ionicLoading.hide();
    })
    //在這里做錯誤處理
    .error(function(err){
        //如果出錯,使用加載器來顯示錯誤信息並在三秒后自動關閉
        $ionicLoading.show({
            template:'無法加載天氣,請稍候再試',
            duration:3000
        });
    });
    //用來把角度值轉換成風向的方法
    $scope.getDirection = function(degree){
        if(degree > 338){
            degree = 360 - degree;
        }
        var index = Math.floor((degree+22)/45);
        return directions[index];
    };
});

  4.6 在餐館視圖中使用卡片和無限滾動

  下面我們進入景點視圖的制作。我們需要顯示一些本地的餐館共游客參考,要實現這個功能,需要從外部加載餐館數據,並使用卡片組件來展示每個餐館的名字和圖片,同時使用無限滾動這樣用戶滾動到列表底部時會加載更多的信息。

  首先我們先來構建餐館視圖的模板文件,新建文件www/views/restaurants/restaurants.html:

<ion-view view-title="附近餐館">
    <ion-content>
        <!-- 創建卡片列表,使用ngRepeat遍歷餐館 -->
        <div class="list card" ng-repeat="restaurant in restaurants">
            <div class="item">
                <h2>{{restaurant.name}}</h2>
                <p>{{restaurant.address}},{{restaurant.city}}</p>
            </div>
            <div class="item item-image">
                <img ng-src="{{restaurant.image_url}}" />
            </div>
        </div>
        <!-- 無限滾動元素會在快要滑到底部的時候調用getRestaurants(),除非已經沒有新數據了 -->
        <ion-infinite-scroll on-infinite="getRestaurants()" ng-if="total > page" immediate-check="false">
        </ion-infinite-scroll>
    </ion-content>
</ion-view>

  然后我們需要給餐館視圖添加一個控制器。這個控制器需要加載餐館數據並在新數據加載完畢時通知唔想滾動組件隱藏。創建文件www/views/restaurant/restaurant.js:

angular.module('starter')
    //創建控制器並注入服務
    .controller('RestaurantsController', function($scope, $http) {
        //創建一些視圖的作用域變量
        $scope.page = 0;
        $scope.total = 1;
        $scope.restaurants = [];
        //定義加載餐館的方法
        $scope.getRestaurants = function() {
            //遞增頁數並發起HTTP請求
            $scope.page++;
            $http.get('http://ionic-in-action-api.herokuapp.com/restaurants?page=' + $scope.page).success(function(response) {
                //獲取餐館列表並把它們添加到ngRepeat操作的餐館數組中
                angular.forEach(response.restaurants, function(restaurant) {
                    $scope.restaurants.push(restaurant);
                });
                //基於API的值更新總頁數
                $scope.total = response.totalPages;
                //廣播事件,告訴無限滾動組件已經加載完成了
                $scope.$broadcast('scroll.infiniteScrollComplete');
                //處理錯誤,廣播事件並打印出錯誤報告
            }).error(function(err) {
                $scope.$broadcast('scroll.infiniteScrollComplete');
                console.log(err);
            });
        };
        //載入頁面的時候從API加載第一頁餐館數據
        $scope.getRestaurants();
    });

  最后,在app.js文件中把視圖添加到狀態中:

            .state('restaurants', {
                url:'/restaurants',
                controller:'RestaurantsController',
                templateUrl:'views/restaurants/restaurants.html'
            });

  我們來預覽一下效果:

  

  4.7 使用幻燈片組件來實現應用介紹

  我們希望用戶在第一次使用我們的旅游應用時能看到一個快速入門的幻燈片介紹。$ionSlideBoxDelegate服務可以用來在程序中控制幻燈片。大多數情況下,我們只需要一些HTML標簽就可以展示幻燈片組件。新建文件www/views/tour/tour.html:

<ion-view view-title="旅游啦" id="tour-view">
    <ion-nav-buttons side="right">
        <a class="button button-clear" href="#/home" nav-clear>goin</a>
    </ion-nav-buttons>

    <ion-slide-box show-pager="true">
        <ion-slide>
            <span class="icon icon-slide ion-document-text"></span>
            <h3>查看預訂信息</h3>
        </ion-slide>
        <ion-slide>
            <span class="icon icon-slide ion-fork"></span>
            <h3>查看附近餐館</h3>
        </ion-slide>
        <ion-slide>
            <span class="icon icon-slide ion-ios-sunny"></span>
            <h3>查看本地天氣</h3>
        </ion-slide>
    </ion-slide-box>
</ion-view>

  然后我們稍微修改一下幻燈片視圖的樣式,新建文件www/views/tour/tour.css:

#tour-view .slider{
    height: 100%;
}
#tour-view .slider-slide{
    padding-top:100px;
    text-align: center; 
}
#tour-view .icon-slide{
    font-size: 20em;
    display: inline-block;
}

  把tour.css引入index.html文件中:

<link href="views/tour/tour.css" rel="stylesheet">

  最后我們來把幻燈片視圖添加到應用的狀態中去,打開app.js文件,添加新狀態:

            .state('tour',{
                url:'/tour',
                templateUrl:'views/tour/tour.html'
            });

  現在預覽一下我們的應用吧~

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM