美文网首页ionic教程
ionic开发Android App学习笔记(二)

ionic开发Android App学习笔记(二)

作者: 镜花水月一梦不觉 | 来源:发表于2015-11-12 19:09 被阅读8162次

    第一个ionic简例分析

    上文中已经将ionic的开发环境搭建完毕,并且创建了一个带有tab页的项目。

    运行效果图:

    运行效果

    项目代码目录图:

    项目代码目录图

    ionic中是使用angularJs和ionic的页面组件来进行开发的,其代码的核心目录为上图中的www目录,代码一般都写在该目录下,主要是html,js和css文件。(上图中的hello.html文件不属于该项目,可忽略)

    整个项目运作的流程如下:

    1.用户请求应用起始页。

    2.用户的浏览器向服务器发起一次HTTP 连接,然后加载index.html 页面,这个页面里面包含了模板。

    3.Angular 被加载到页面中,等待页面加载完成,然后查找ng-app 指令,用来定义模板边界。

    4.Angular 遍历模板,查找指令和绑定关系,这将触发一系列动作:注册监听器、执行一些DOM 操作、从服务器获取初始化数据。这项工作的最后结果是,应用将会启动起来,并且模板被转换成了DOM 视图。

    5.连接到服务器去加载需要展示给用户的其他数据。

    下面具体分析一下代码:

    index.html

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
        <title></title>
    
        <link href="lib/ionic/css/ionic.css" rel="stylesheet">
        <link href="css/style.css" rel="stylesheet">
    
        <!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
        <link href="css/ionic.app.css" rel="stylesheet">
        -->
    
        <!-- ionic/angularjs js -->
        <script src="lib/ionic/js/ionic.bundle.js"></script>
    
        <!-- cordova script (this will be a 404 during development) -->
        <script src="cordova.js"></script>
    
        <!-- your app's js -->
        <script src="js/app.js"></script>
        <script src="js/controllers.js"></script>
        <script src="js/services.js"></script>
      </head>
      <body ng-app="starter">
        <!--
          The nav bar that will be updated as we navigate between views.
        -->
        <ion-nav-bar class="bar-stable">
          <ion-nav-back-button>
          </ion-nav-back-button>
        </ion-nav-bar>
        <!--
          The views will be rendered in the <ion-nav-view> directive below
          Templates are in the /templates folder (but you could also
          have templates inline in this html file if you'd like).
        -->
        <ion-nav-view></ion-nav-view>
    
      </body>
    </html>
    

    index.html中 head中就是配置一些适配参数和引用一些js,包括app.js,controllers.js,services.js 自己定义的3个js文件。

    body中是绘制整个页面的,在body这个标签上加上了ng-app 标记,表示body这个标签之内的东西由angularJs来解析,angularJs承包了body这个鱼塘,并且起了一个名字:starter,这样就会告诉Angular 去管理页面上的所有DOM 元素。

    body中就是一些ionic的界面组件了,每个组件的解释和用法可参考该网站:组件api

    在最后一行,有个ion-nav-view组件,该组件的作用为:在app启动时,$stateProvider就会检查url,检查它的索引匹配状态,然后尝试将对应的html加载到<ion-nav-view>内。

    tabs.html

    <!--
    Create tabs with an icon and label, using the tabs-positive style.
    Each tab's child <ion-nav-view> directive will have its own
    navigation history that also transitions its views in and out.
    -->
    <ion-tabs class="tabs-icon-top tabs-color-active-positive">
    
      <!-- Dashboard Tab -->
      <ion-tab title="Status" icon-off="ion-ios-pulse" icon-on="ion-ios-pulse-strong" href="#/tab/dash">
        <ion-nav-view name="tab-dash"></ion-nav-view>
      </ion-tab>
    
      <!-- Chats Tab -->
      <ion-tab title="Chats" icon-off="ion-ios-chatboxes-outline" icon-on="ion-ios-chatboxes" href="#/tab/chats">
        <ion-nav-view name="tab-chats"></ion-nav-view>
      </ion-tab>
    
      <!-- Account Tab -->
      <ion-tab title="Account" icon-off="ion-ios-gear-outline" icon-on="ion-ios-gear" href="#/tab/account">
        <ion-nav-view name="tab-account"></ion-nav-view>
      </ion-tab>
    
    
    </ion-tabs>
    

    该html即为整个布局页面,3个tab页:Status,Chats,Account

    定义了3个tab,每个tab中有一个ion-nav-view ,还定义了tab 页选中和没选中时的图标,以及指定超链接目标的 URL

    tab-dash.html

    <ion-view view-title="Dashboard">
      <ion-content class="padding">
        <div class="list card">
          <div class="item item-divider">Recent Updates</div>
          <div class="item item-body">
            <div>
              There is a fire in <b>sector 3</b>
            </div>
          </div>
        </div>
        <div class="list card">
          <div class="item item-divider">Health</div>
          <div class="item item-body">
            <div>
              You ate an apple today!
            </div>
          </div>
        </div>
        <div class="list card">
          <div class="item item-divider">Upcoming</div>
          <div class="item item-body">
            <div>
              You have <b>29</b> meetings on your calendar tomorrow.
            </div>
          </div>
        </div>
      </ion-content>
    </ion-view>
    

    此html中是纯的静态代码,用到了较多的ionic组件,可参考上面的api了解每个组件的用法。

    -----重点来了-----

    tab-chats.html

    <ion-view view-title="Chats">
      <ion-content>
        <ion-list>
          <ion-item class="item-remove-animate item-avatar item-icon-right" ng-repeat="chat in chats" type="item-text-wrap" href="#/tab/chats/{{chat.id}}">
            <img ng-src="{{chat.face}}">
            <h2>{{chat.name}}</h2>
            <p>{{chat.lastText}}</p>
            <i class="icon ion-chevron-right icon-accessory"></i>
    
            <ion-option-button class="button-assertive" ng-click="remove(chat)">
              Delete
            </ion-option-button>
          </ion-item>
        </ion-list>
      </ion-content>
    </ion-view>
    

    这是第2个tab页,是一个list列表。首先定义了页面的标题:Chats ,然后定义了一个列表,接着定义列表的item,其中有这么一句:ng-repeat="chat in chats" , ng-repeat是angular的标签,表示遍历,后面的写法应该就是遍历chats了,那么问题来了:chats从哪来的呢?

    带着疑问继续看代码

    先看一下angularJs中的一个重要概念

    $scope概念

    $scope 的使用贯穿整个 Angular App 应用,它与数据模型相关联,同时也是表达式执行的上下文.有了 $scope 就在视图和控制器之间建立了一个通道,基于作用域视图在修改数据时会立刻更新 $scope,同样的 $scope 发生改变时也会立刻重新渲染视图。其实就是双向绑定。

    有了 $scope 这样一个桥梁,应用的业务代码可以都在 controller 中,而数据都存放在controller 的 $scope 中。

    $scope概念图

    $scope 的作用

    $scope 对象在 Angular 中充当数据模型的作用,也就是一般 MVC 框架中 Model 得角色.但又不完全与通常意义上的数据模型一样,因为 $scope 并不处理和操作数据,它只是建立了视图和 HTML 之间的桥梁,让视图和 Controller 之间可以友好的通讯。

    再进一步系统的划分它的作用和功能:

    1. 提供了观察者可以监听数据模型的变化
    2. 可以将数据模型的变化通知给整个 App
    3. 可以进行嵌套,隔离业务功能和数据
    4. 给表达式提供上下文执行环境

    在 Javascript 中创建一个新的执行上下文,实际就是用函数创建了一个新的本地上下文,在 Angular 中当为子 DOM 元素创建新的作用域时,其实就是为子 DOM 元素创建了一个新的执行上下文。

    $scope 生命周期

    Angular 中也有一个'事件'的概念,比如当一个绑定了 ng-model的 input 值发生变化时,或者一个 ng-click 的 button 被点击时,Angular 的事件循环就会启动.事件循环是 Angular 中非常非常核心的一个概念,因为不是本文主旨所以不多说,感兴趣的可以自己看看资料.这里事件就在 Angular 执行上下文中处理,$scope 就会对定义的表达式求值.此时事件循环被启动, Angular 会监控应用程序内所有对象,脏值检查循环也会启动。

    $scope 的生命周期有4个阶段:

    1. 创建
    控制器或者指令(ng-controller)创建时, Angular 会使用 $injector 创建一个新的作用域,然后在控制器或指令运行时,将作用域传递进去。
    
    1. 链接
    Angular 启动后会将所有 $scope 对象附加或者说链接到视图上,所有创建 $scope 对象的函数也会被附加到视图上.这些作用域将会注册当 Angular 上下文发生变化时需要运行的函数.也就是 $watch 函数, Angular 通过这些函数或者何时开始事件循环。
    
    1. 更新
    一旦事件循环开始运行,就会开始执行自己的脏值检测.一旦检测到变化,就会触发 $scope 上指定的回调函数。
    
    1. 销毁
    通常来讲如果一个 $scope 在视图中不再需要, Angular 会自己清理它.当然也可以通过 $destroy() 函数手动清理。
    

    可以参考以下网站来进一步了解$scope :

    http://www.tuicool.com/articles/nUzMz2J 或者

    http://blog.csdn.net/aitangyong/article/details/40267583?utm_source=tuicool&utm_medium=referral

    笔者总结一下:

    一个controller对应了一个$scope对应了一个DOM,强调一下是DOM,不一定是body,也有可能是div,总之就是一个标签都可以配置一个ng-controller。而这个DOM范围内,都可以引用$scope中存储的数据或者函数

    接着上面的问题:chats从哪来的呢?

    从来的解释中可以看出,这个chats定是存储在tab-chats.html对应的某个$scope中,由于tab-chats.html中没有直接的DOM指出一个具体的controller,否者我们就直接去controller中找$scope就行了。

    但是我们在app.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'
    // '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) {
            $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 && window.cordova.plugins.Keyboard) {
                    cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
                    cordova.plugins.Keyboard.disableScroll(true);
    
                }
                if (window.StatusBar) {
                    // org.apache.cordova.statusbar required
                    StatusBar.styleLightContent();
                }
            });
        })
        .config(function ($stateProvider, $urlRouterProvider, $ionicConfigProvider) {
            $ionicConfigProvider.platform.ios.tabs.style('standard');
            $ionicConfigProvider.platform.ios.tabs.position('bottom');
            $ionicConfigProvider.platform.android.tabs.style('standard');
            $ionicConfigProvider.platform.android.tabs.position('bottom');
    
            $ionicConfigProvider.platform.ios.navBar.alignTitle('center');
            $ionicConfigProvider.platform.android.navBar.alignTitle('left');
    
            $ionicConfigProvider.platform.ios.backButton.previousTitleText('').icon('ion-ios-arrow-thin-left');
            $ionicConfigProvider.platform.android.backButton.previousTitleText('').icon('ion-android-arrow-back');
    
            $ionicConfigProvider.platform.ios.views.transition('ios');
            $ionicConfigProvider.platform.android.views.transition('android');
        })
        .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('tab', {
                    url: '/tab',
                    // abstract: true 表明此状态不能被显性激活,只能被子状态隐性激活
                    abstract: true,
                    templateUrl: '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.chats', {
                    url: '/chats',
                    views: {
                        'tab-chats': {
                            templateUrl: 'templates/tab-chats.html',
                            controller: 'ChatsCtrl'
                        }
                    }
                })
                .state('tab.chat-detail', {
                    url: '/chats/:chatId',
                    views: {
                        'tab-chats': {
                            templateUrl: 'templates/chat-detail.html',
                            controller: 'ChatDetailCtrl'
                        }
                    }
                })
    
                .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('/tab/dash');
    
        });
    

    直接看到以下代码:

    .state('tab.chats', {
        url: '/chats',
        views: {
            'tab-chats': {
                templateUrl: 'templates/tab-chats.html',
                controller: 'ChatsCtrl'
            }
        }
    })
    

    tab-chats.html页面对应的controller为ChatsCtrl,这时候我们就可以去controllers.js中找到名字为ChatsCtrl的controller了。

    controllers.js

    angular.module('starter.controllers', [])
    
    .controller('DashCtrl', function($scope) {})
    
    .controller('ChatsCtrl', function($scope, Chats) {
      $scope.chats = Chats.all();
      $scope.remove = function(chat) {
        Chats.remove(chat);
      };
    })
    
    .controller('ChatDetailCtrl', function($scope, $stateParams, Chats) {
      $scope.chat = Chats.get($stateParams.chatId);
    })
    
    .controller('AccountCtrl', function($scope) {
      $scope.settings = {
        enableFriends: true
      };
    });
    

    看到 $scope.chats = Chats.all(); 给chats赋值了,此处的chats即为前面提到问题的答案,tab-chats.html页面的chats的来源即为此处,并且已经赋值了。

    那么问题又来了,它(chats )的值是什么呢?

    从上面的代码可以看出它的值为:Chats.all() 但是Chats是什么呢?

    其实Chats和$scope一样都是服务,只不过$scope是系统服务(就是有系统来定义的),而Chats是自定义服务,需要自己写代码定义。

    我们在services.js中可以找到Chats服务。

    services.js代码

    angular.module('starter.services', [])
    
    .factory('Chats', function() {
    
      var chats = [{
        id: 0,
        name: 'Ben Sparrow',
        lastText: 'You on your way?',
        face: 'https://pbs.twimg.com/profile_images/514549811765211136/9SgAuHeY.png'
      }, {
        id: 1,
        name: 'Max Lynx',
        lastText: 'Hey, it\'s me',
        face: 'https://avatars3.githubusercontent.com/u/11214?v=3&s=460'
      }, {
        id: 2,
        name: 'Adam Bradleyson',
        lastText: 'I should buy a boat',
        face: 'https://pbs.twimg.com/profile_images/479090794058379264/84TKj_qa.jpeg'
      }, {
        id: 3,
        name: 'Perry Governor',
        lastText: 'Look at my mukluks!',
        face: 'https://pbs.twimg.com/profile_images/598205061232103424/3j5HUXMY.png'
      }, {
        id: 4,
        name: 'Mike Harrington',
        lastText: 'This is wicked good ice cream.',
        face: 'https://pbs.twimg.com/profile_images/578237281384841216/R3ae1n61.png'
      }];
    
      return {
        all: function() {
          return chats;
        },
        remove: function(chat) {
          chats.splice(chats.indexOf(chat), 1);
        },
        get: function(chatId) {
          for (var i = 0; i < chats.length; i++) {
            if (chats[i].id === parseInt(chatId)) {
              return chats[i];
            }
          }
          return null;
        }
      };
    });
    

    上面的factory('Chats', function() 中的 Chats 自定义的服务名称 ,该服务定义了返回值,返回了3个函数:all() ,

    remove() ,get() 。

    所以上面的Chats.all()的值是什么也就很清楚了,即是var chats 这个对象数组。

    关于如何自定义服务,可参考这个网站 http://my.oschina.net/tanweijie/blog/295067

    从上面的网站中,了解到这一点:

    在Angular里面,services作为单例对象在需要到的时候被创建,只有在应用生命周期结束的时候(关闭浏览器)才会被清除。而controllers在不需要的时候就会被销毁了。

    说的是服务的生命周期,很重要的一点。

    基本上分析了demo中的大部分,不想写了,下一次再写,分析一下app.js中的一些东西。

    文章中用到项目地址 :https://github.com/viphsx123/myApp

    完。

    参考链接:

    http://my.oschina.net/blogshi/blog/316745

    http://www.tuicool.com/articles/nUzMz2J

    http://blog.csdn.net/aitangyong/article/details/40267583?utm_source=tuicool&utm_medium=referral

    http://my.oschina.net/tanweijie/blog/295067

    相关文章

      网友评论

      • Minzou丶怪兽:Cordova 怎么直接打开Angular 里面index.html 的子页面呢~~
      • ab8ad17e4204:楼主还继续写么,写的真棒
        镜花水月一梦不觉:@薰薰V 优化的方案也有啊,后台要做些缓存的操作,适合开发一些比较小型的app吧
        f185c6d31aa0:@镜花水月一梦不觉 那有没有什么优化方案?那这么说ionic不适合用于开发android手机的app
        镜花水月一梦不觉:@沐日光所去 :flushed: 不准备写了,ionic在android手机上运行比较卡,而且现在混合式方案也比较多,ionic的实际应用范围不怎么广
      • fa54021d36e2:写的非常漂亮,正在学习,解决了我好多迷惑,谢谢 :+1:

      本文标题:ionic开发Android App学习笔记(二)

      本文链接:https://www.haomeiwen.com/subject/rxnhhttx.html