首页 > 代码库 > 5 选项卡、高级列表和表单组件--汇率应用

5 选项卡、高级列表和表单组件--汇率应用

  简介:本节课我们将会构建一个显示比特币和其他货币的实时汇率及历史汇率的应用。界面会使用Ionic的选项卡组件,其中包含三个选项卡,分别为查看的当前市场汇率、查看历史汇率图标以及资金管理。我们将会学到如何在选项卡中使用导航窗口,如果想要在使用选项卡的同时维护用户界面状态,那么掌握这个技术将非常重要。此外,我们还会学到如何在不同选项卡中缓存外部来源加载的数据,这样可以提高假造速度,避免不必要的HTTP请求。

  下面我们还是同上节课一样,先来看一下基本的应用界面:

  看完上面的图示,我们对将要开发的应用有了一个基本的认识,下面进入开发环节。

  5.1 配置应用项目

  我们来手动创建一个新的Ionic项目,基本环境配置,我们在第二节课已经讲过了,下面直接创建项目:

  打开终端,执行命令:$ ionic start exr

  等待执行完成。

  进入exr文件夹:$ cd exr/

  执行启动应用服务的命令:$ ionic serve

  可以看见默认配置好的界面如下图所示:

  技术分享

  

  5.2 ionTabs:添加选项卡和导航

  用编辑器打开项目文件夹,我们的第一个任务是添加导航元素:ionNavBar和ionNavView组件。ionNavBar可以根据当前选项卡自动更新标题栏,ionNavView会显示tabs模板。

  下面我们打开index.html文件,做如下修改:

<!-- body元素关联了ngApp -->
<body ng-app="starter">
    <ion-nav-bar class="bar-positive">
        <!-- 添加了ionNavBackButton来显示或隐藏返回按钮 -->
        <ion-nav-back-button class="button-clear">
          <i class="ion-chevron-left"></i>Back
        </ion-nav-back-button>
    </ion-nav-bar>
    <!-- 添加ionNavView组件 -->
    <ion-nav-view></ion-nav-view>
</body>

  这样我们就可以把组件添加到模板中,并用它们来渲染路由。现在我们来声明第一个路由和模板。

  打开app.js文件,做如下修改:

// Ionic Starter App
angular.module(‘starter‘, [‘ionic‘])
//声明config方法并注入服务
.config(function($stateProvider, $urlRouterProvider) {
  //给标签声明状态
  $stateProvider
    .state(‘tabs‘, {
    url: ‘/tabs‘,
    templateUrl: ‘views/tabs/tabs.html‘
  });
  //设置默认路由
  $urlRouterProvider.otherwise(‘/tabs‘);
});

  然后我们来给应用添加选项卡容器和三个选项卡。Ionic提供了一个非常强大的组件,用来快速创建选项卡,具体的选项卡数量并没有限制,不过由于空间限制,通常只有2~5个。我们可以在任何位置使用选项卡,除了ionContent指令,因为在ionContent中使用ionTabs会导致CSS冲突。

  Ionic提供了两个选项卡组件:ionTabs和ionTab。下面我们来给应用模板添加标签,创建新文件www/views/tabs/tabs.html:

<ion-tabs class="tabs-icon-top tabs-positive">
    <ion-tab title="实时汇率" icon-on="ion-social-bitcoin" icon-off="ion-social-bitcoin-outline">
    </ion-tab>
    <ion-tab title="历史汇率" icon-on="ion-ios-analytics" icon-off="ion-ios-analytics-outline">
    </ion-tab>
    <ion-tab title="资金管理" icon-on="ion-ios-cog" icon-off="ion-ios-cog-outline">
    </ion-tab>
</ion-tabs>

  上面就是选项卡的声明,非常简单,对于单个选项卡来说,只有title属性是必须的,现在我们的选项卡是空的,预览的效果是酱紫的~

  技术分享

  5.3 给每个选项卡添加ionNavView

  下面我们来给每个选项卡添加ionNavView组件来加载组件,这样每个选项卡都需要维护自己的导航历史。我们可以给某个选项卡单独使用返回按钮,而不是直接给应用使用。这样我们可以在选项卡之前切换视图,同时每个视图也可以保留自己当前的浏览状态,切换选项卡视图的时候可以不受影响,返回按钮可以单独控制。

  首先,我们需要向选项卡中添加ionNavView组件,需要分别给这些组件设置一个名字,从而可以引用它们。在Ionic应用中,只能有一个未命名的ionNavView,并且它一定是默认视图。每个选项卡还会有一个ui-sref属性,用来把选项卡图标转换成按钮,从而可以在选项卡之间切换。

  现在我们来打开www/views/tabs/tabs.html文件,做如下更新,来给每个标签设置独立的视图:

<ion-tabs class="tabs-icon-top tabs-positive">
    <!-- 添加ui-sref来基于选项卡选择改动视图 -->
    <ion-tab title="Rates" icon-on="ion-social-bitcoin" icon-off="ion-social-bitcoin-outline" ui-sref="tabs.rates">
        <!-- 给每个选项卡添加ionNavView组件并命名 -->
        <ion-nav-view name="rates-tab"></ion-nav-view>
    </ion-tab>
    <ion-tab title="History" icon-on="ion-ios-analytics" icon-off="ion-ios-analytics-outline" ui-sref="tabs.history">
        <ion-nav-view name="history-tab"></ion-nav-view>
    </ion-tab>
    <ion-tab title="Currencies" icon-on="ion-ios-cog" icon-off="ion-ios-cog-outline" ui-sref="tabs.currencies">
        <ion-nav-view name="currencies-tab"></ion-nav-view>
    </ion-tab>
</ion-tabs>

  下面我们在app.js的config()方法中添加新视图的路由。uiRouter有嵌套状态的特性,可以声明带层级的状态。打开app.js文件,做如下更新:

// Ionic Starter App
angular.module(‘starter‘, [‘ionic‘])
    //声明config方法并注入服务
    .config(function($stateProvider, $urlRouterProvider) {
        //给标签声明状态
        $stateProvider
            .state(‘tabs‘, {
                url: ‘/tabs‘,
                //把选项卡的状态改为抽象,这样可以使用它的子选项卡
                abstract: true,
                templateUrl: ‘views/tabs/tabs.html‘
            })
            //使用点号来声明tabs.rates状态
            .state(‘tabs.rates‘, {
                //声明路由的URL,这是一个子路由,所以它会被添加到父URL之后
                url: ‘/rates‘,
                //汇率视图的目标视图名称以及视图模板
                views: {
                    ‘rates-tab‘: {
                        templateUrl: ‘views/rates/rates.html‘
                    }
                }
            })
            //声明历史视图
            .state(‘tabs.history‘, {
                url: ‘/history‘,
                views: {
                    ‘history-tab‘: {
                        templateUrl: ‘views/history/history.html‘
                    }
                }
            })
            //声明资金视图
            .state(‘tabs.currencies‘, {
                url: ‘/currencies‘,
                views: {
                    ‘currencies-tab‘: {
                        templateUrl: ‘views/currencies/currencies.html‘
                    }
                }
            });
            //设置默认路由为汇率视图
        $urlRouterProvider.otherwise(‘/tabs/rates‘);
    });

  最后我们来给这三个选项卡添加默认模板,新建文件www/views/rates/rates.html:

<ion-view title="实时汇率">
    <ion-content>
    </ion-content>
</ion-view>

  新建文件www/views/history/history.html:

<ion-view title="历史汇率">
    <ion-content>
    </ion-content>
</ion-view>

  新建文件www/views/currencies/currencies.html:

<ion-view title="资金管理">
    <ion-content>
    </ion-content>
</ion-view>

  现在我们来预览应用就可以在切换视图的时候看到各自的标题栏啦~

技术分享

  5.4 加载并显示当前的比特币汇率-->汇率视图选项卡

  我们应用的第一个选项卡的展示内容就是显示当前比特币市场价对应不同货币的汇率。在这里,我们可以实现加载实时数据并显示到选项卡中。选项卡内会显示最后更新的日期以及一个货币列表,包含当前的价格和趋势。为了辅助实现货币列表,首先需要创建一个currencies服务。打开app.js文件,将以下代码添加至文件结尾,记得要去掉之前代码结尾的分号:

//使用angular的factory方法来注册服务
    .factory(‘Currencies‘, function() {
        //创建货币数组并设置默认的选择状态
        return [
            { code: ‘AUD‘, text: ‘Australian Dollar‘, selected: true },
            { code: ‘BRL‘, text: ‘Brazilian Real‘, selected: false },
            { code: ‘CAD‘, text: ‘Canadian Dollar‘, selected: true },
            { code: ‘CHF‘, text: ‘Swiss Franc‘, selected: false },
            { code: ‘CNY‘, text: ‘Chinese Yuan‘, selected: true },
            { code: ‘EUR‘, text: ‘Euro‘, selected: true },
            { code: ‘GBP‘, text: ‘British Pound Sterling‘, selected: true },
            { code: ‘IDR‘, text: ‘Indonesian Rupiah‘, selected: false },
            { code: ‘ILS‘, text: ‘Israeli New Sheqel‘, selected: false },
            { code: ‘MXN‘, text: ‘Mexican Peso‘, selected: true },
            { code: ‘NOK‘, text: ‘Norwegian Krone‘, selected: false },
            { code: ‘NZD‘, text: ‘New Zealand Dollar‘, selected: false },
            { code: ‘PLN‘, text: ‘Polish Zloty‘, selected: false },
            { code: ‘RON‘, text: ‘Romanian Leu‘, selected: false },
            { code: ‘RUB‘, text: ‘Russian Ruble‘, selected: true },
            { code: ‘SEK‘, text: ‘Swedish Krona‘, selected: false },
            { code: ‘SGD‘, text: ‘Singapore Dollar‘, selected: false },
            { code: ‘USD‘, text: ‘United States Dollar‘, selected: true },
            { code: ‘ZAR‘, text: ‘South African Rand‘, selected: false }
        ];
    });

  上面的Currencies服务是一个数组,包含一组对象,对象中是货币信息,code是货币的标准名称,text是货币的名称,selected属性用来确定对应的货币是否显示在列表中。现在我们创建并注册了服务,我们可以在应用中的任何地方使用它。

  第一个要用到Currencies服务的地方是实时汇率视图的控制器。这个控制器会从BitcionAverage API加载当前的汇率数据,加载完毕后,它会把数据存到Currencies服务中,这些数据可以在作用域中使用。现在我们来创建汇率视图的控制器,创建文件www/views/rates/rates.js:

angular.module(‘starter‘)
    //声明RatesController控制器并注入要用的服务
    .controller(‘RatesController‘, function($scope, $http, Currencies) {
        //立刻把货币服务的数据赋值给作用域
        $scope.currencies = Currencies;
        //加载数据
        $scope.load = function() {
            //给bitcoinaverage发送HTTP请求,获取当前汇率
            $http.get(‘https://api.bitcoinaverage.com/ticker/all‘).success(
                function(tickers) {
                    console.log(tickers);
                    //遍历货币列表,把数据存储到货币服务
                    angular.forEach($scope.currencies, function(currency) {
                        currency.ticker = tickers[currency.code];
                        //把响应中的时间戳换成JS日期对象
                        currency.ticker.timestamp = new Date(currency.ticker.timestamp);
                    });
                });
        };
        //第一次加载控制器的时候触发一次加载
        $scope.load();
    });

  这个控制器会在load()方法被调用时使用$http服务加载数据。Currencies服务被注入并存储在作用域中,这样汇率视图就可以使用它来展示所有的数据。同时你还把当前的汇率存储到了Currencies服务中,这样后面就可以方便的使用它这个数据对象,并且可以传递到其他地方并被多次使用,这也是共享数据的方法之一。

  现在,我们已经可以加载数据了,下一步是把数据显示到视图里。打开rates.html文件,我们来修改模板,让其遍历货币信息并显示出来控制器加载的数据:

<ion-view title="实时汇率">
    <ion-content>
        <ion-list>
            <!-- ngRepeat遍历货币并过滤出没有激活的货币 -->
            <ion-item ng-repeat="currency in currencies | filter:{selected:true}">
                {{currency.code}} - {{currency.text}}
                <!-- 会在当前价格等于过去24小时平均价格的时候显示 -->
                <span class="price" ng-if="currency.ticker.last == currency.ticker[‘24h_avg‘]">
                    {{currency.ticker.last || ‘0.00‘}}<br />0.00
                </span>
                <!-- 会在当前价格小于过去24小时平均价格时候显示 -->
                <span class="price negative" ng-if="currency.ticker.last < currency.ticker[‘24h_avg‘]">{{currency.ticker.last}}<br /><span class="icon ion-arrow-down-b"></span>{{currency.ticker[‘24h_avg‘] - currency.ticker.last | number:2}}
                </span>
                <!-- 会在当前价格大于过去24小时平均价格的时候显示 -->
                <span class="price positive" ng-if="currency.ticker.last > currency.ticker[‘24h_avg‘]">{{currency.ticker.last}}<br /><span class="icon ion-arrow-up-b"></span>{{currency.ticker.last - currency.ticker[‘24h_avg‘] | number:2}}
                </span>
            </ion-item>
        </ion-list>
    </ion-content>
    <ion-footer-bar class="bar-dark">
        <!-- ionFooterBar会保留最后一次加载数据时的尾部 -->
        <h1 class="title">Updated {{currencies[0].ticker.timestamp | date:‘mediumTime‘}}</h1>
    </ion-footer-bar>
</ion-view>

  我们来理解一下上面的这段代码,这里用到了list组件,然后用ngRepeat给每个货币元素都创建了一个列表元素,在ngRepeat里有一个过滤器,它会过滤掉selected的值为false的货币。在每个列表元素内,我们建立了三个span标签,用来显示上千的价格以及和过去24小时平均值的对比趋势,我们用ngIf来进行条件判断如何显示。在包裹容器后面,我们加了一个ionFooterBar组件,将页尾自动定位到选项卡的后面。

  然后我们添加一些CSS样式来美化汇率视图,打开www/css/styles.css文件,加入如下的样式:

.item .price { font-weight: bold; font-size: 13px; color: #fff; position: absolute; background: #666; right: 15px; height: 42px; top: 5px; width: 80px; text-align: center; padding: 6px; line-height: 1.2em; }
.item .price.positive { background: #66cc33; }
.item .price.negative { background: #ef4e3a; }

  现在打开index.html文件,将rates.js文件引入进去:

<script src="views/rates/rates.js"></script>

  然后,将汇率视图的控制器加入到app.js文件的状态中:

            .state(‘tabs.rates‘, {
                //声明路由的URL,这是一个子路由,所以它会被添加到父URL之后
                url: ‘/rates‘,
                //汇率视图的目标视图名称以及视图模板
                views: {
                    ‘rates-tab‘: {
                        templateUrl: ‘views/rates/rates.html‘,
                        controller:‘RatesController‘
                    }
                }
            })

  打开浏览器预览效果如下:

技术分享

 

  5.5 在同一个选项卡视图中显示货币细节信息-->汇率视图选项卡二级视图

  在汇率视图中,我们实现了查看当前汇率列表数据内容,但是我们还想对每条货币查看它的细节数据,那么我们就需要再创建一个子视图,让我们可以从汇率视图导航到子视图以达到查看细节数据的功能,当我们看完细节数据,还可以通过BACK按钮返回到汇率视图中。

  首先我们来创建汇率视图子视图--详情视图的控制器,它不需要请求其他的数据,直接使用Currencies服务已经加载好的数据就可以了。新建文件www/views/detail/details.js:

angular.module(‘starter‘)
    //创建控制器DetailsController并注入服务
    .controller(‘DetailsController‘, function($scope, $stateParams, $state, Currencies) {
        //遍历所有的货币,找到需要的货币并存储到作用域中
        angular.forEach(Currencies, function(currency) {
            if (currency.code === $stateParams.currency) {
                $scope.currency = currency;
            }
        });
        //如果货币和数据没有设置,返回到汇率视图
        if (angular.isUndefined($scope.currency.ticker)) {
            $state.go(‘tabs.rates‘);
        }
    });

  创建DetailsController控制器时,需要传入currency这个参数,用$stateParams服务来访问这个参数的值(其实就是code,对于这部分参数迷糊的,可以把它们打印出来,就能明白了),拿到参数后,遍历货币信息,找到匹配的code值,然后把货币模型赋值给$scope作用域。

  然后我们来创建详情视图的模板,创建文件www/views/detail/detail.html:

<ion-view view-title="{{currency.code}} 详情">
    <ion-content>
        <ion-list>
            <ion-item>
                现价:<span class="badge badge-stable">{{currency.ticker.last}}</span>
            </ion-item>
            <ion-item>
                估价:<span class="badge badge-stable">{{currency.ticker.ask}}</span>
            </ion-item>
            <ion-item>
                出价:<span class="badge badge-stable">{{currency.ticker.bid}}</span>
            </ion-item>
            <ion-item>
                24h均价:<span class="badge badge-stable">{{currency.ticker[‘24h_avg‘]}}</span>
            </ion-item>
            <ion-item>
                交易量:<span class="badge badge-stable icon ion-social-bitcoin">{{currency.ticker.total_vol | number:2}}</span>
            </ion-item>
            <ion-item ui-sref="tabs.history({currency:currency.code})" class="item-icon-right">
                历史信息:<span class="icon ion-arrow-right-b"></span>
            </ion-item>
        </ion-list>
    </ion-content>
    <ion-footer-bar class="bar-dark">
        <h1 class="title">Updated {{currency.ticker.timestamp | date:‘mediumTime‘}}</h1>
    </ion-footer-bar>
</ion-view>

  上面模板中用列表和标记来显示数据,即给元素加上badge和badge-[color]的样式,这个很简单,历史信息用ui-sref属性,用于实现页面跳转。

  建好详情视图的模板和控制器后,我们来向app.js的状态中添加路由来声明新状态,打开app.js文件:

            //声明详情视图
            .state(‘tabs.detail‘, {
                url: ‘/detail/:currency‘,
                views: {
                    ‘rates-tab‘: {
                        templateUrl: ‘views/detail/detail.html‘,
                        controller:‘DetailsController‘
                    }
                }
            });

  详情视图的状态和汇率视图重用同一个视图,:currency参数会被设置为一个货币code,然后传入状态中,这样来确定显示哪种货币,在详情视图的控制器中使用$stateParams来访问这个值。

  最后,修改汇率视图模板,使其点击列表元素项时实现页面跳转到详情视图,打开rates.html:

<ion-view title="实时汇率" hide-back-button="true">
    <ion-content>
        <ion-list>
            <!-- ngRepeat遍历货币并过滤出没有激活的货币 -->
            <ion-item ng-repeat="currency in currencies | filter:{selected:true}" ui-sref="tabs.detail({currency: currency.code})">

  hide-back-button="true"的意思是让视图不要显示返回按钮,ui-sref="tabs.detail({currency: currency.code})"是链接到详情视图。

  现在我们来预览应用,点击列表项即可以看到下面详情视图:

技术分享

  5.6 刷新汇率视图并显示帮助信息

  现在我们已经可以载入汇率并查看详情,但是我们的汇率视图只能看一页内容,无法刷新数据。下面我们来实现更新数据的功能。更新常用的方法是ionRefresher组件,用户在屏幕上下拉并松手,即可触发数据刷新,这个组件可以让任何ionContent组件拥有一个隐藏的界面,当用户下拉内容区域的时候显示出来,如果用户下拉足够长度并松手,它会调用一个函数来重载数据,重载完成后,组件会隐藏。此外,我们还需要给用户提供一个快速帮助的界面,告知用户屏幕内容。

  要使用ionRefresher组件,我们需要更新汇率模板和控制器,打开rates.html文件:

<ion-view title="实时汇率" hide-back-button="true">
    <ion-content>
        <!-- ionRefresher组件必须是ionContent的第一个元素,它会调用load()方法 -->
        <ion-refresher on-refresh="load()" pulling-text="下拉刷新">
        </ion-refresher>

  然后我们来修改汇率视图的控制器,因为组件本身不知道数据什么时候加载完毕,所以它不会自动隐藏,我们需要再控制器里添加一个广播事件,来通知刷新组件数据加载完毕了可以隐藏了。

  打开rates.js文件:

        $scope.load = function() {
            //给bitcoinaverage发送HTTP请求,获取当前汇率
            $http.get(‘https://api.bitcoinaverage.com/ticker/all‘)
                .success(
                    function(tickers) {
                        //遍历货币列表,把数据存储到货币服务
                        angular.forEach($scope.currencies, function(currency) {
                            currency.ticker = tickers[currency.code];
                            //把响应中的时间戳换成JS日期对象
                            currency.ticker.timestamp = new Date(currency.ticker.timestamp);
                        });
                    })
                //链式调用一个finally()方法,它会在http请求完成后触发,无论成功或者失败,广播scroll.refreshComplete事件,这样ionRefresher组件知道何时隐藏
                .finally(function() {
                    $scope.$broadcast(‘scroll.refreshComplete‘);
                });
        };

  现在,我们实现了刷新功能,看下预览效果~

技术分享

  现在,我们来实现弹出帮助信息的功能。要使用到的是$ionPopover组件,这个组件一般会在首页显示一个按钮,单机按钮,会弹出一个页面。创建文件www/views/rates/help-popover.html:

<ion-popover-view>
    <!-- 在弹出框中使用ionHeaderBar -->
    <ion-header-bar>
        <h1 class="title">关于比特币</h1>
    </ion-header-bar>
    <!-- 添加ionContent和描述内容 -->
    <ion-content>
        <div class="padding">
            这里显示了最后一个比特币的交易价格,并比较它的24小时均价。
        </div>
        <div class="padding">
            <a href="">bitcoin average</a>api
        </div>
    </ion-content>
</ion-popover-view>

  然后打开汇率视图控制器声明弹出页面。打开rates.js文件:

        $scope.currencies = Currencies;
        //声明弹出框的模板URL,并把父作用域设置为它的作用域
        $ionicPopover.fromTemplateUrl(‘views/rates/help-popover.html‘, {
                scope: $scope,
            })
            //加载模板之后,把弹出框赋值给作用域
            .then(function(popover) {
                $scope.popover = popover;
            });
        //作用域中显示弹出框的方法,需要传入$event
        $scope.openHelp = function($event) {
            $scope.popover.show($event);
        };
        //监听$destroy事件,当视图销毁时会广播,这时销毁弹出框
        $scope.$on(‘$destroy‘, function() {
            $scope.popover.remove();
        });

  下面来添加一个按钮触发弹出页面,打开rates.html:

<ion-view title="实时汇率" hide-back-button="true">
    <!-- 使用ionNavButtons来声明顶部导航区域的按钮 -->
    <ion-nav-buttons side="primary">
        <!-- 添加一个按钮,使用ngClick来调用openHelp方法并传入$event -->
        <button class="button" ng-click="openHelp($event)">About</button>
    </ion-nav-buttons>

  预览效果:

技术分享

 

   5.7 历史视图绘制

  如果用户想要看到过去一个月内某种货币和比特币汇率的变化情况。我们会用到Highcharts绘图库和一个Angular的Highcharts命令highcharts-ng。

  我们先来配置第三方库。先安装Bower,打开终端,执行命令:$ sudo npm install -g bower

  然后安装这两个库:Highcharts绘图库和Angular的Highcharts包装库highcharts-ng。

  执行下面的命令,Ionic会自动下载并配置这两个库:

  $ ionic add highcharts-release#4.0.4 highcharts-ng#0.0.7

  或者下载第三方库,解压复制到www/lib文件夹下面也可以:

  http://www.highcharts.com/download -->highcharts绘图库

  https://github.com/pablojim/highcharts-ng -->highcharts-ng

  下载完成后,将这两个库引入到index.html文件中:

    <script src="http://www.mamicode.com/lib/highcharts-release/adapters/standalone-framework.js"></script>
    <script src="http://www.mamicode.com/lib/highcharts-release/highcharts.js"></script>
    <script src="http://www.mamicode.com/lib/highcharts-ng/dist/highcharts-ng.js"></script>

  然后将highcharts-ng模块声明为项目依赖,打开app.js文件:

angular.module(‘starter‘, [‘ionic‘, ‘highcharts-ng‘])

  打开之前建立的历史汇率选项卡模板,添加一个下拉列表组件来切换汇率,还需要配置好Highcharts组件。需要使用一个只包含一个元素的嵌入列表来创建下拉列表容器,打开history.html文件:

<ion-view title="历史汇率" hide-back-button="true">
    <ion-content>
        <!-- 使用嵌入列表来包含下拉列表 -->
        <div class="list list-inset">
            <label class="item item-input item-select">
                <div class="input-label">
                    currency
                </div>
                <!-- 使用ngChange和ngModel来跟踪值的变化 -->
                <select ng-change="changeCurrency()" ng-model="history.currency">
                    <!-- 给每个激活状态的货币建一个选项 -->
                    <option ng-repeat="currency in currencies | filter:{selected:true}" value="{{currency.code}}" ng-selected="history.currency == currency.code">
                        {{currency.code}} - {{currency.text}}
                    </option>
                </select>
            </label>
        </div>
        <!-- highchart组件会接受一个config属性,这个属性是一个图表对象 -->
        <highchart config="chart"></highchart>
    </ion-content>
</ion-view>

  下面我们来配置历史汇率选项卡的控制器,来加载数据并配置图表。新建文件www/views/history/history.js:

angular.module(‘starter‘)
    //创建控制器并注入服务
    .controller(‘HistoryController‘, function($scope, $http, $state, $stateParams, Currencies) {
        //给history模型赋值一个下拉列表,默认为USD
        $scope.history = {
            currency: $stateParams.currency || ‘USD‘
        };
        //把货币列表存储在作用域中
        $scope.currencies = Currencies;
        //changeCurrency()方法会读取下拉列表的值并用它更新当前的状态
        $scope.changeCurrency = function() {
            $state.go(‘tabs.history‘, { currency: $scope.history.currency });
        };
        //chart声明的对象会被Highcharts命令转换为图标
        $scope.chart = {
            options: {
                chart: {
                    type: ‘line‘
                },
                legend: {
                    enabled: false
                }
            },
            title: {
                text: null
            },
            yAzis: {
                title: null
            },
            xAxis: {
                type: ‘datetime‘
            },
            series: []
        };
        //基于被选中的货币加载历史信息
        $http.get(‘https://api.bitcoinaverage.com/history/‘ + $scope.history.currency + ‘/per_hour_monthly_sliding_window.csv‘)
            .success(function(prices) {
                //把prices字符串分割成一个数组,每个元素都是一行价格
                prices = prices.split(/\n/);
                //创建一个空坐标系数组
                var series = {
                    data: []
                };
                //遍历每行价格
                angular.forEach(prices, function(price, index) {
                    //把每一行用逗号分隔成数组
                    price = price.split(‘,‘);
                    //解析并格式化时间和价格值
                    var date = new Date(price[0].replace(‘ ‘, ‘T‘)).getTime();
                    var value = http://www.mamicode.com/parseFloat(price[3]);
                    //如果日期和值合法,把这个点添加到坐标系数组中
                    if (date && value > 0) {
                        series.data.push([date, value]);
                    }
                });
                //把完整的坐标系数组添加到图标数据中
                $scope.chart.series.push(series);
            });
        //监听$ionicView.enter事件,在没有缓存的情况下重置货币模型
        $scope.$on(‘$ionicView.enter‘, function() {
            $scope.history = {
                currency: $stateParams.currency || ‘USD‘
            };
        });
    });

  将历史视图控制器引入index.html文件:

    <script src="http://www.mamicode.com/views/history/history.js"></script>

  更新历史视图的状态声明,打开app.js文件:

            //声明历史视图
            .state(‘tabs.history‘, {
                url: ‘/history?currency‘,
                views: {
                    ‘history-tab‘: {
                        templateUrl: ‘views/history/history.html‘,
                        controller:‘HistoryController‘
                    }
                }
            })

  现在我们来查看一下历史视图的页面:

技术分享

  5.8 货币管理选项卡:支持重新排序和开关功能

  货币管理选项卡需要实现货币列表的重新排序以及货币显示的开关功能。

  首先我们需要给货币管理选项卡添加一个模板,然后使用ionReorderButton来实现重新排序的功能。重新排序只能用在ionList指令上,要使用它,可以设置reordering状态为true/false,重排图标会根据这个值显示或者隐藏,如果被激活,可以使用图标拖动元素到新的位置,然后控制器会自动更新模型。打开www/views/currencies/currencies.html文件:

<ion-view title="资金管理">
    <!-- 添加一个切换state.reordering值的按钮 -->
    <ion-nav-buttons side="primary">
        <button class="button" ng-click="state.reordering = !state.reordering">重排</button>
    </ion-nav-buttons>
    <ion-content>
        <!-- 使用show-reorder来声明列表可以被重新排列,以及需要使用的模型 -->
        <ion-list show-reorder="state.reordering">
            <ion-item ng-repeat="currency in currencies">
                {{currency.code}} - {{currency.text}}
                <!-- ionReorderButton必须被包含进来,并且在元素被移动之后调用一个方法 -->
                <ion-reorder-button class="ion-navicon" on-reorder="move(currency, $fromIndex, $toIndex)"></ion-reorder-button>
            </ion-item>
        </ion-list>
    </ion-content>
</ion-view>

  现在我们已经创建了一个可以重新排序的货币列表。ionList组件使用show-reorder属性来判断是否显示ionReorderButton,它俩一起使用实现了重排的工鞥呢,导航栏中的按钮用来切换state.reordering属性,它又会触发重排是否显示。on-reorder方法会在重排结束时被调用,它会传入两个特殊的参数,$fromIndex和$toIndex,这是列表中元素的下标值,以此确定元素的移动位置。

  创建货币管理视图控制器文件www/views/currencies/currencies.js:

angular.module(‘starter‘)
    //声明控制器并注入服务
    .controller(‘CurrenciesController‘, function($scope, Currencies) {
        //把货币关联到作用域
        $scope.currencies = Currencies;
        //声明默认的reordering状态
        $scope.state = {
            reordering: false
        };
        //监听状体变化,在离开选项卡的时候退出重排状态
        $scope.$on(‘$stateChangeStart‘, function() {
            $scope.state.reordering = false;
        });
        //处理元素的移动,移动元素在列表中的位置
        $scope.move = function(currency, fromIndex, toIndex) {
            $scope.currencies.splice(fromIndex, 1);
            $scope.currencies.splice(toIndex, 0, currency);
        };
    });

  然后我们来给列表添加开关项,打开currencies.html文件做如下修改:

<ion-view title="资金管理">
    <!-- 添加一个切换state.reordering值的按钮 -->
    <ion-nav-buttons side="primary">
        <button class="button" ng-click="state.reordering = !state.reordering">重排</button>
    </ion-nav-buttons>
    <ion-content>
        <!-- 使用show-reorder来声明列表可以被重新排列,以及需要使用的模型 -->
        <ion-list show-reorder="state.reordering">
            <!-- 添加item-toggle类来应用开关样式 -->
            <ion-item class="item-toggle" ng-repeat="currency in currencies">
                {{currency.code}} - {{currency.text}}
                <!-- 声明一个标签,添加toggle类 -->
                <label class="toggle toggle-balanced">
                    <!-- 使用checkout输入框并给它的模型值为currency.selected -->
                    <input type="checkbox" ng-model="currency.selected">
                    <!-- 添加开关图标需要的元素 -->
                    <div class="track">
                        <div class="handle"></div>
                    </div>
                </label>
                <!-- ionReorderButton必须被包含进来,并且在元素被移动之后调用一个方法 -->
                <ion-reorder-button class="ion-navicon" on-reorder="move(currency, $fromIndex, $toIndex)"></ion-reorder-button>
            </ion-item>
        </ion-list>
    </ion-content>
</ion-view>

  然后,我们把货币管理控制器引入到index.html文件中:

<script src="http://www.mamicode.com/views/currencies/currencies.js"></script>

  最后,我们来将货币管理视图状态添加到app.js文件中:

            //声明货币视图
            .state(‘tabs.currencies‘, {
                url: ‘/currencies‘,
                views: {
                    ‘currencies-tab‘: {
                        templateUrl: ‘views/currencies/currencies.html‘,
                        controller:‘CurrenciesController‘
                    }
                }
            })

  现在我们来预览一下货币管理的界面吧~

技术分享

 

  现在,我们的这款货币应用已经完成喽~

 

5 选项卡、高级列表和表单组件--汇率应用