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

Posted 姜腾腾

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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来声明顶部导航区域的按钮 -->
    以上是关于5 选项卡高级列表和表单组件--汇率应用的主要内容,如果未能解决你的问题,请参考以下文章

Android:如何在选项卡内从一个片段导航到另一个片段? [关闭]

返回片段后ListView为空

相同的片段与不同选项卡上的列表视图

Android导航组件:如何保存片段状态

当返回到“导航架构组件”中的同一选项卡时,嵌套片段的状态会丢失

我在 viewpager 选项卡中的片段不刷新