zoukankan      html  css  js  c++  java
  • 二识angularJS

      前言:记得三月份时下定决心说每天要更新一篇博客,学习点新东西,实践下来发现太不现实,生活中的事情很多,再喜欢也不能让它一件占据生活的全部吧,所以呢,以后顺其自然吧。之前有一篇‘初识angular’因为离职找工作等一系列原因,搁置了好久,今早看看,继续写以前的已经无法继续,索性重新开始,有时间再修该之前的吧。

    二识angular(基于angular官方文档)

    地址:https://angularjs.org/

    一,基础:先看html代码

    <!doctype html>
    <html ng-app><!--ng-app声明页面的这个部分将基于angular-->
      <head>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
      </head>
      <body>
        <div>
          <label>Name:</label>
          <input type="text" ng-model="yourName" placeholder="Enter a name here">
          <!--ng-model将表单和模型联系在一起,这里的即yourname,这样你在表单中输入的内容将出现在后文中调用该变量的地方,{{yourName}}-->
          <h1>Hello {{yourName}}!</h1>
        </div>
      </body>
    </html>

    构建angular应用,首先应该应该引入资源文件,其次,应该声明,也就是ng-app指令,告诉应用它是基于angular的。第三,angular是通过各种指令来实现的,因此,第三个步骤就是学习各种指令。

    上面代码中我们用到了一个ng-mode指令,l它将表单和模型联系在一起,能够在应用中‘瞬间’获得表单输入的内容。比如,上面的代码,你在表单中输入的内容会立刻出现在hello的后面;而且,无论yourName变量何时发生改变它的所有引用也会立即更新。

    二,加入一些控制

    第一步,我们实现了一个简单的数据的双向绑定,但是,实际的应用场景中,情况比这复杂的多,很所时候,我们需要收集,判断,处理等等。因此,我们需要加入一些控制。

    数据绑定:data-binding是一种无论model何时改变都会自动更新的方式,就如上文讲到的‘瞬间’获得;同时,他也会在视图发生改变时更新model。这一点让烦人的dom操作成了一件你不在需要担心的事。($scope.$apply();这段代码暂且放在这里,它的作用之一就是可以传播model的变化,通常情况下,我们在页面中直接加入的ng-model是可以“瞬间”更新的,但是如果是在jQuery的ajax中,并不是瞬间实现数据同步的,我们需要将改变传播出去,这样才可以起作用。但是,并不提倡滥用这个方法,一般angular JS自带的方法会默认调用该方法。)

    控制器:controller,暂且叫它控制器吧,它是和dom元素相关的一系列行为,它让你将这些行为用干净可读性强的表单来表达,取代以前的样板式的通过注册回调函数,或者监听模型是否发生改变来更新form。

    简单的原生JavaScript:不同于其他框架,angular是简单的JavaScript项目,你不需要有专门的样板或者调用及继承来让你的东西匹配angular,这一点让你的代码很容易测试,维护,重用,而且从复杂的样板式调用中解放出来。

    下面看一个可以添加未做事项清单的小应用;

    html代码:

    <!doctype html>
    <html ng-app="todoApp">
        <head>
            <meta charset="utf-8" />
            <script type="text/javascript" src="js/angular.min.js"></script>
            <script type="text/javascript" src="js/todo.js"></script>
            <style>
                .done-true {text-decoration: line-through;color: grey;}
                ul,li{list-style: none;}
            </style>
        </head>
        <body>
            <h2>需要做的事情清单</h2>
            <!--这个控制器内部的元素行为将被由ng-controller这个命令所指定的控制器TodoListController所控制。-->
            <div ng-controller="TodoListController as todoList">
                <!--{{todoList.todos.length}}{{todoList.todos.length}}数据调用-->
                <span>您共有{{todoList.todos.length}}件需要做的事情,其中的{{todoList.todos.length}}项还未完成</span> [
                <!--ng-click="todoList.archive()"这也是一个方法调用,显示还未完成的清单列表-->
                <a href="" ng-click="todoList.archive()">仅显示未完成清单</a> ]
                <ul>
                    <li ng-repeat="todo in todoList.todos">
                        <label class="checkbox">
                        <input type="checkbox" ng-model="todo.done">
                        <span class="done-{{todo.done}}">{{todo.text}}</span>
                      </label>
                    </li>
                </ul>
                <!--调用方法ng-submit="todoList.addTodo()"-->
                <form ng-submit="todoList.addTodo()">
                    <input type="text" ng-model="todoList.todoText" size="30" placeholder="添加你将要做的事情">
                    <input class="btn-primary" type="submit" value="添加">
                </form>
            </div>
        </body>
    </html>

     (1),ng-controller="TodoListController as todoList"。

        注意这个as,后文我们调用TodoListController 时只需要使用todolist代替就好了,如:

          ng-submit="todoList.addTodo()

     (2),ng-repeat="todo in todoList.todos"。

        将 todoList.todos用todo来指代,后文可直接todo.xxx的形式来调用todos里面的数据。

     (3), <span class="done-{{todo.done}}">{{todo.text}}</span>。

        类名中一样可以使用表达式,并且包含在双引号内部。

    .done-true {
      text-decoration: line-through;
      color: grey;
    }

     (4),ng-click="todoList.archive()。

        事件调用。

    注意看这个方法,语法几乎就是JavaScript,只是有时候加上了一些属于angular的方法。比如本例中的angular.forEach()。angular中可以直接使用JavaScript。

    //定义控制器的方法archive,显示清单库中所有还未完成的事情。
            todoList.archive = function() {
                var oldTodos = todoList.todos;
                todoList.todos = [];
                angular.forEach(oldTodos, function(todo) {
                    if(!todo.done) todoList.todos.push(todo);//如果事件未完成,则加入事件清单里面;
                });
            };

    js代码:定义了一个模块todoApp,同时给这个模块添加了一组数据和三个方法。

    angular.module('todoApp', [])
        //所有的行为控制写在控制器里面;
        .controller('TodoListController', function() {
            var todoList = this;//定义当前控制器的对象;
            todoList.todos = [{//数据源
                    text: '学习 AngularJS',
                    done: true
                },
                {
                    text: '建一个 AngularJS app',
                    done: false
                }
            ];
            //定义控制器的方法addTodo,添加未完成的事情。
            todoList.addTodo = function() {
                todoList.todos.push({
                    text: todoList.todoText,
                    done: false
                });
                todoList.todoText = '';
            };
            //定义控制器的方法remaining,还未完成的事情数目
            todoList.remaining = function() {
                var count = 0;
                angular.forEach(todoList.todos, function(todo) {
                    count += todo.done ? 0 : 1;
                });
                return count;
            };
            //定义控制器的方法archive,显示清单库中所有还未完成的事情。
            todoList.archive = function() {
                var oldTodos = todoList.todos;
                todoList.todos = [];
                angular.forEach(oldTodos, function(todo) {
                    if(!todo.done) todoList.todos.push(todo);
                });
            };
        });

    三,和后台交互

    深链接(deep link):一个深链接,反应出用户此刻处在APP的那个流程中,这对于用户将页面存为书签和发送邮件很方便,往返型的APP可以自动获得以上这些,但是ajax类型的应用,则不可能实现这些。angular JS将深链接和桌面应用的类APP行为结合起来。

    表单验证(Form Validation):客户端的表单验证是一个好的用户体验中很重要的一个版块。angularJS让你不用写JavaScript代码就可以声明验证规则。通过类名结合布尔值来判断,实现表单的验证。

    服务端交互(Server Communication):angular JS提供嵌入的服务,这些服务基于XHR和其他很多不同种类的第三方库提供的后台。promises能够很好地简化你的代码,通过管理异步的回调数据。下面的例子,我们将通过AngularJS 的AngularFire 库来为一个简单的angular JS APP搭建一个Firebase后台。

    先看代码:

    主页面,主要加载资源文件和提供显示视图的容器,ng-view可以结合路由配置实现同一个页面内部不同子内容的加载。不同的路由配置下,加载不同的模板。

    <!doctype html>
    <html ng-app="project">
    
        <head>
            <meta charset="UTF-8">
            <link rel="stylesheet" type="text/css" href="css/angular.css"/>
            <link rel="stylesheet" href="css/bootstrap.min.css" />
            <link rel="stylesheet" href="css/font-awesome.css" />
            <script type="text/javascript" src="js/jquery-1.9.1.min.js" ></script>
            <script type="text/javascript" src="js/bootstrap.min.js" ></script>
            <script type="text/javascript" src="js/angular.min.js" ></script>
            <script type="text/javascript" src="js/angular-resource.min.js" ></script>
            <script type="text/javascript" src="js/angular-route.min.js" ></script>
            <script src="https://cdn.firebase.com/js/client/2.0.4/firebase.js"></script>
            <script src="https://cdn.firebase.com/libs/angularfire/0.9.0/angularfire.min.js"></script>
            <script type="text/javascript" src="js/project.js" ></script>
            <script type="text/javascript" src="js/project-list.js" ></script>
        </head>
        <body>
            <div class="container">
                <h2>JavaScript Projects</h2>
                <!--我们通过这个div,作为加载局部页面或者视图的地方。它周围的页面会保持静态,
                当我们在这个模块中动态加载时,这样我们可以在一系列对象和表单之间切换,
                来添加新的项目或者编辑已经存在的项目。-->
                <!--动态加载不同的子内容,通过路由配置结合模板来实现,这之外的部分,保持静态-->
                <div ng-view></div>
            </div>
        </body>
    </html>

    列表模板:通过遍历取到的数据,生成列表。

    <!--ng-model="projectList.search",将输入域和search属性绑定,这个选择器用来选择只包含用户输入的关键字的对象。-->
    <input type="text" ng-model="projectList.search" class="search-query" id="projects_search" placeholder="Search">
    <table>
        <thead>
            <!--表头-->
            <tr>
                <th>Project</th>
                <th>Description</th>
                <th>
                    <!--一个连接到/new的路由,这个路由已经在project.js中配置过,
                    既然我们遵循web的精神,没有必要在链接上注册回调函数,我们只是简单的导航到一个新的路由
                    它会自动更新浏览器的浏览历史,并且使deep-linking可用。
                    但是,不同于普通的server round trip application应用(服务器往返应用),这个navigation event会在浏览器中被立即渲染-->
                    <a href="#!/new"><i class="icon-plus-sign"></i></a>
                </th>
            </tr>
        </thead>
        <!--表格主体-->
        <tbody>
            <!--ng-repeat="project in projectList.projects | filter:projectList.search | orderBy:'name'"
                ng-repeat用来展开一个数据集合,(遍历),对于集合中的每一条数据,angular都会执行一次生成操作
            -->
            <!--filter,用来选择一个集合的子集,该子集是包含projectList.search关键字的一个集合。
            orderBy,指定子集的排序规则-->
            <tr ng-repeat="project in projectList.projects | filter:projectList.search | orderBy:'name'">
                <!--遍历生成表格的每一行-->
                <td>
                    <a ng-href="{{project.site}}" target="_blank">{{project.name}}</a>
                </td>
                <td>{{project.description}}</td>
                <td>
                    <a ng-href="#!/edit/{{project.$id}}"><i class="icon-pencil"></i></a>
                </td>
            </tr>
        </tbody>
    </table>

    修改或者添加模板:重点是表单验证。

    <!--创建一个名为myForm的表单,在这里我们会声明验证规则,来显示错误输入和不可操作的表单-->
    <form name="myForm">
        <!--添加一个error类,当输入不合法时,$pristine意思是如果表单未被使用,也就是输入为空。-->
        <div class="control-group" ng-class="{error: myForm.name.$invalid && !myForm.name.$pristine}">
            <label>Name</label>
            <!--required:当没有输入时,将输入域置为无效-->
            <input type="text" name="name" ng-model="editProject.project.name" required>
                <!--show这个错误信息,当input name有requeired error时-->
            <span ng-show="myForm.name.$error.required && !myForm.name.$pristine" class="help-inline">
            Required {{myForm.name.$pristine}}</span>
        </div>
    
        <div class="control-group" ng-class="{error: myForm.site.$invalid && !myForm.site.$pristine}">
            <label>Website</label>
            <input type="url" name="site" ng-model="editProject.project.site" required>
            <span ng-show="myForm.site.$error.required && !myForm.site.$pristine" class="help-inline">
            Required</span>
            <span ng-show="myForm.site.$error.url" class="help-inline">Not a URL</span>
        </div>
    
        <label>Description</label>
        <textarea name="description" ng-model="editProject.project.description"></textarea>
    
        <br>
        <a href="#!/" class="btn">Cancel</a>
         <!--ng-disabled 将save按钮置为不可操作,当表单没有输入或者输入有误时-->
        <button ng-click="editProject.save()" ng-disabled="myForm.$invalid" class="btn btn-primary">Save</button>
        <button ng-click="editProject.destroy()" ng-show="editProject.project.$id" class="btn btn-danger">Delete</button>
    </form>

    JavaScript文件:

    项目主代码:project.js。主要包括取数据,路由配置和显示列表、添加项目、修改项目三个controller的定义。(注意里面的各种注入的依赖,在function里面声明)

    //定义module,通过它你可以安装(加载)angular已有的服务和定义新的命令,服务和选择器等等。
    angular.module('project', ['ngRoute', 'firebase'])
    //模块可以依赖于其它模块,这里project需要firebase来处理这个应用的可持续。
        .value('fbURL', 'https://ng-projects-list.firebaseio.com/')
        //.value可以用来定义一个单独的对象,可以注入到其它的controllers和servises中去。前面是变量名,后面是值。
        .service('fbRef', function(fbURL) {
            return new Firebase(fbURL)//返回请求地址
        })
        .service('fbAuth', function($q, $firebase, $firebaseAuth, fbRef) {//$firebase firegase提供的一个服务
            var auth;
            return function() {
                if(auth) return $q.when(auth);
                var authObj = $firebaseAuth(fbRef);
                if(authObj.$getAuth()) {
                    return $q.when(auth = authObj.$getAuth());
                }
                var deferred = $q.defer();
                authObj.$authAnonymously().then(function(authData) {
                    auth = authData;
                    deferred.resolve(authData);
                });
                return deferred.promise;
            }
        })
    /**
     * Projects是firebase的一个实例,在project模块中已经定义过了,
     * 它提供对应用进行增加,删除和更新的方法(接口),
     * 它的目标是将服务器交互抽象化。
     * 它让controllers集中处理行为而不是复杂的服务器连接之类。
     **/
        .service('Projects', function($q, $firebase, fbRef, fbAuth, projectListValue) {
            var self = this;
            this.fetch = function() {//取数据,也就是和后台交互。这里是基于firebase,也可以是通过其他形式来进行数据调用,比如ajax
                if(this.projects) return $q.when(this.projects);
                return fbAuth().then(function(auth) {
                    var deferred = $q.defer();
                    var ref = fbRef.child('projects-fresh/' + auth.auth.uid);
                    var $projects = $firebase(ref);
                    ref.on('value', function(snapshot) {
                        if(snapshot.val() === null) {
                            //我们可以通过将一个对象的值设为null来删除它。
                            $projects.$set(projectListValue);
                        }
                        //$asArray()一个方法,以数组形式返回firebase里面的数据。
                        self.projects = $projects.$asArray();//取到数据并以数组形式返回
                        deferred.resolve(self.projects);
                    });
    
                    //Remove projects list when no longer needed.
                    ref.onDisconnect().remove();
                    return deferred.promise;
                });
            };
        })
        /* 
         * .config()可以用来对已经存在的服务进行配置,
         * 这里我们将对$routeProvider进行配置,来让它适用于局部路径。
         * */
        .config(function($routeProvider) {
            var resolveProjects = {
                projects: function(Projects) {
                    return Projects.fetch();//获取数据,依赖于Projects模块
                }
            };
    
            $routeProvider
            /**
             * '/'当URL是/的时候,将会加载List.html到view里,同时和ProjectListController相关联,
             * 通过阅读路由定义,你可以立即得到一个关于APP结构的概览。
             * **/
                .when('/', {
                    /**
                     * controller定义一个controller function可以和使用ng-congroller的dom元素关联
                     * 或者和一个view template通过在路由配置里面指定从而实现关联。
                     * **/
                    controller: 'ProjectListController as projectList',//声明controller
                    templateUrl: 'list.html',
                    resolve: resolveProjects//数据调用
                })
                /**
                 * '/edit/:projectId',这个路由定义我们使用了冒号,我们可以通过冒号来让URL的一个部分可以被controller调用。(类似于传参吧)
                 * 现在,edit controller可以使用projectId作为参数,来找到需要edit的对象。
                 * **/
                .when('/edit/:projectId', {
                    controller: 'EditProjectController as editProject',
                    templateUrl: 'detail.html',
                    resolve: resolveProjects
                })
                .when('/new', {
                    controller: 'NewProjectController as editProject',
                    templateUrl: 'detail.html',
                    resolve: resolveProjects
                })
                //.otherwise()指定,当当前路由不满足已经配置的所有路由时要显示的界面。
                .otherwise({
                    redirectTo: '/'
                });
        })
    //显示列表
        .controller('ProjectListController', function(projects) {
            var projectList = this;
            projectList.projects = projects;//把数据源导入
        })
    //新增项目
        //可以通过$location服务,来使用浏览器的location对象
        .controller('NewProjectController', function($location, projects) {
            var editProject = this;
            //当视图中的save按钮被点击时,执行
            editProject.save = function() {
                projects.$add(editProject.project).then(function(data) {
                    /**
                     * 我们用.path()方法来改变location的'deep-linking'location。
                     * URL的改变,会立即激活新的路由,并且让应用显示对应的view,这里也就是
                     * **/
                    $location.path('/');//添加之后跳转到默认的列表页
                });
            };
        })
    //修改项目
        .controller('EditProjectController',
        //$routeParams:这里我们让angular注入$routeParams,通过它来使从路由配置中提取出来的参数可用。
            function($location, $routeParams, projects) {
                var editProject = this;
                //projectId:提取URL中的projectId,它允许controller利用应用的deep-linking信息进行加工。(生成其它内容)
                var projectId = $routeParams.projectId,
                    projectIndex;
    
                editProject.projects = projects;
                projectIndex = editProject.projects.$indexFor(projectId);
                editProject.project = editProject.projects[projectIndex];
                //当用户单击删除按钮时执行。
                editProject.destroy = function() {
                    editProject.projects.$remove(editProject.project).then(function(data) {
                        $location.path('/');//删除之后跳转到主页。也就是默认的列表页
                    });
                };
    
                editProject.save = function() {
                    editProject.projects.$save(editProject.project).then(function(data) {
                        $location.path('/');//保存之后跳转到默认的列表页
                    });
                };
            });

    要点分析:

    (1),angular.module:这个语句定义一个angular模块或者说是小的‘应用’,是一个相对独立的单元,它可以拥有自己的一系列‘私有物’。

    (2),angular.module.value:定义一个独立的angular对象,他可以注入到其它的controllers或者service中去,我的理解是类似于js中的静态变量的感觉。

    (3),angular.module.service:定义一个服务,可以注入其它内容,在服务中引用,本身也可以被引用。

    (4),angular.module.factory:和service类似。

    (5),angular.module.controller:定义controllers。

    (6),angular.module.config:用来对已经存在的服务进行配置。

    数据代码(模拟数据):project-list.js

    angular.module('project').value('projectListValue', [{
            name: 'AngularJS',
            site: 'http://angularjs.org',
            description: 'HTML enhanced for web apps!'
        },
        {
            name: 'Angular',
            site: 'http://angular.io',
            description: 'One framework. Mobile and desktop.'
        },
        {
            name: 'jQuery',
            site: 'http://jquery.com/',
            description: 'Write less, do more.'
        },
        {
            name: 'Backbone',
            site: 'http://backbonejs.org/',
            description: 'Models for your apps.'
        },
        {
            name: 'SproutCore',
            site: 'http://sproutcore.com/',
            description: 'A Framework for Innovative web-apps.'
        },
        {
            name: 'Polymer',
            site: 'https://www.polymer-project.org/',
            description: 'Reusable components for the modern web.'
        },
        {
            name: 'Spine',
            site: 'http://spinejs.com/',
            description: 'Awesome MVC Apps.'
        },
        {
            name: 'Cappucino',
            site: 'http://www.cappuccino-project.org/',
            description: 'Objective-J.'
        },
        {
            name: 'Knockout',
            site: 'http://knockoutjs.com/',
            description: 'MVVM pattern.'
        },
        {
            name: 'GWT',
            site: 'http://www.gwtproject.org/',
            description: 'JS in Java.'
        },
        {
            name: 'Ember',
            site: 'http://emberjs.com/',
            description: 'Ambitious web apps.'
        },
        {
            name: 'React',
            site: 'https://facebook.github.io/react/',
            description: 'A JavaScript library for building user interfaces.'
        }
    ])

    四,创建组件

    指令(Directives):指令是angular JS中一个独特而又强大的特点,它让你创建新的html标签,只在你的应用范围内有效。

    可重用组件(Reusable Components):我们通过指令来创建可重用组件,组件让你能够隐藏复杂的dom结构,css和行为,它让你只关注应用做什么或者应用的外观中的一个方面。将两者分开来处理。

    本地化(Localization):本地化是一个严谨或者说正式的APP中非常重要的一个方面。angular js的本地化感知过滤器和阻挡指令给你独特的模块,让你的应用适用于所有区域。

    先看一个示例代码:

    html:

    <!DOCTYPE html>
    <!--ng-app激活这个页面区域的APP 模块,这个模块包括BeerCounter controller,而且依赖于components module
    它包含html扩展命令<tabs>和<pane>组件。-->
    <html ng-app="app">
        <head>
            <meta charset="UTF-8">
            <title></title>
            <link rel="stylesheet" href="../backend/css/bootstrap.min.css" />
            <link rel="stylesheet" href="../backend/css/font-awesome.css" />
            <script type="text/javascript" src="../backend/js/jquery-1.9.1.min.js" ></script>
            <script type="text/javascript" src="../backend/js/bootstrap.min.js" ></script>
            <script type="text/javascript" src="../js/angular.min.js" ></script>
            <script src="components.js"></script>
            <script src="app.js"></script>
        </head>
    
        <body class="container">
            <!--我们通过普通的tabs扩展了html的标签库,它抽象了渲染tabs所需要的复杂的html结构和相关行为,
            生成一个可读性强的视图,同时也是一个可重用的序列。-->
            <tabs>
                <!--组件可以以html属性的形式携带参数,在这里,title属性指定了tabs的文本;
                    Localization一个演示angular中num,data等的数据格式和本地化;
                    两个pane分别代表两个tab切换卡的内容。一个标题为Localization,另一个标题为Pluralization
                -->
                <pane title="Localization">
                    <span>Date: {{ '2012-04-01' | date:'fullDate' }}</span><br>
                    <span>Currency: {{ 123456 | currency }}</span><br>
                    <span>Number: {{ 98765.4321 | number }}</span><br>
                </pane>
                <!--Pluralization一个演示angular多元化的例子,注意数量改变时,beer的不同形式。-->
                <pane title="Pluralization">
                    <!--我们通过BeerCounter controller来建立基于本地的计数规则-->
                    <div ng-controller="BeerCounter">
                        <div ng-repeat="beerCount in beers">
                            <!--ng-pluralize指令为每个区域选择正确的显示格式,不同于英语,其它语言通常都有基于包含项目数组的复杂的显示规则
                            count="beerCount",绑定到number属性,它成为选择显示格式的选择器
                            when="beerForms"绑定到多元化规则,这些规则会因为语言个地区的不同组合而不同。-->
                            <ng-pluralize count="beerCount" when="beerForms"></ng-pluralize>
                        </div>
                    </div>
                </pane>
            </tabs>
        </body>
    
    </html>

    去掉注释和引用后的主体html代码:

    <body class="container">
            <tabs>
                <pane title="Localization">
                    <span>Date: {{ '2012-04-01' | date:'fullDate' }}</span><br>
                    <span>Currency: {{ 123456 | currency }}</span><br>
                    <span>Number: {{ 98765.4321 | number }}</span><br>
                </pane>
                <pane title="Pluralization">
                    <div ng-controller="BeerCounter">
                        <div ng-repeat="beerCount in beers">
                            <ng-pluralize count="beerCount" when="beerForms"></ng-pluralize>
                        </div>
                    </div>
                </pane>
            </tabs>
        </body>

    html中已经初始化了应用,这里简要分析下这段代码:这段代码用到了两个自定义标签,tabs和pane。tabs是我们常见的切换卡,代码中通过pane的title属性将自己和tabs标题关联起来。title的值就是它所对应的tabs的标题。所以,简要抽象这个组件的话可以看成下面的内容:

    <tabs>
        <pane title='我是选项卡标题'>
              <div>我是选项卡内容</div>
        </pane>
        <pane title='标题1'>
              <div>我是选项卡内容</div>
        </pane>
        <pane title='标题2'>
             <div>我是选项卡内容</div>
        </pane>
    </tabs>

    JavaScript:

    components.js

    这个文件中定义了两个组件,tabs和pane。pane包含在tabs之中。pane之中调用了tabs的controller,所以可以在内部调用它的方法,即addPane();

    angular.module('components', [])
    //通过module的.directive()方法来为我们的应用定义新的标签,比如这里定义了tabs标签,
        .directive('tabs', function() {
            return {
                //restrict定义html形式,是E的话,组件只能是el形式
                restrict: 'E',
    //            指定当angular使用扩展的标签替换tabs时它应该将原始内容放置于由ng-transclude指令指定的位置.
                transclude: true,
    //            组件需要私有的scope,以便它的视图属性不会突然在tabs之外被修改,
    //            如果你确实需要暴露内容,你可以声明input/output 的内容,这一点可以参考后文的pans的定义
                scope: {},
    //            和应用一样,组件也可以拥有一个controllers,来提供组件的行为,$scope为组件的scope, $element为组件所在的元素
                controller: function($scope, $element) {
    //                $scope组件的scope
    //                $element要放置组件的元素,调用组件时传入。
                    var panes = $scope.panes = [];
    //                发布一个select()方法,用来在tab之间切换视图。
                    $scope.select = function(pane) {
                        angular.forEach(panes, function(pane) {
                            pane.selected = false;//通过布尔值控制是否被选中。这里是将所有的pane都设为非选中状态
                        });
                        pane.selected = true;//当前传入的这个设为选中状态
                    }
    //                组件通常需要结合在一起,形成一个单元,在这里,我们的pane标签,将通过addPane()方法,将自己注册到它的容器<tabs>里面。
                    this.addPane = function(pane) {
                        if(panes.length == 0) $scope.select(pane);
                        panes.push(pane);
                    }
                },
    //            将被浏览器渲染替换tabs里面的内容,注意,模板内部也可以使用指令
                template: '<div class="tabbable">' +
                    '<ul class="nav nav-tabs">' +
    //                ng-class="{active:pane.selected}"我们创建active类名,来为处于激活状态的tab设置样式。
                    '<li ng-repeat="pane in panes" ng-class="{active:pane.selected}">' +
                    '<a href="" ng-click="select(pane)">{{pane.title}}</a>' +
                    '</li>' +
                    '</ul>' +
    //                ng-transclude标记tabs的内容将会放置在哪里
                    '<div class="tab-content" ng-transclude></div>' +
                    '</div>',
    //                replace: true告诉angular tabs将会被模板替换,而不是放在它之后
                replace: true
            };
        })
    
        .directive('pane', function() {
            return {
    //            require: '^tabs',说明pane组件必须在tabs组件的内部,这让pane组件能够使用tabs组件的方法,在这里也就是addPane();
                require: '^tabs',
                restrict: 'E',
                transclude: true,
                scope: {
                    title: '@'
                },
                link: function(scope, element, attrs, tabsController) {
    //            tabsController.addPane(scope);我们之前说过,我们需要tabs作为我们的容器,这里我们传递它的实例
                    tabsController.addPane(scope);
                },
                template: '<div class="tab-pane" ng-class="{active: selected}" ng-transclude>' +
                    '</div>',//将替换pane标签的内容
                replace: true
            };
        })

    app.js

     这是app模块的定义,这里注入了对于components的依赖,这就保证了我们可以在应用中使用自己定义的指令;同时,这个文件中也定义了多元化规则,比如,是英语时如何显示,其它语言时又如何显示。

    //app模块声明了一个对components模块的依赖,这确保了components模块中的指令,同时也会被加载到应用中.
    angular.module('app', ['components'])
    //$locale服务包含了一系列和本地化相关的内容,是每一种语言,本地化的混合体.
        .controller('BeerCounter', function($scope, $locale) {
    //设置beers的计数数组,我们将会迭代这个数组,然后看beers的变化情况,也就是本地化
            $scope.beers = [0, 1, 2, 3, 4, 5, 6];
    //$locale.id == 'en-us':基于本地情况创建不同的多元化规则,在真实的应用中,我们会加载包含每种语言本地化和相关规则的模块。
            if($locale.id == 'en-us') {
                //$scope.beerForms 适应于英语的多元化规则。
                $scope.beerForms = {
                    0: 'no beers',
                    one: '{} beer',
                    other: '{} beers'
                };
            } else {
                $scope.beerForms = {
                    0: 'žiadne pivo',
                    one: '{} pivo',
                    few: '{} pivá',
                    other: '{} pív'
                };
            }
        });

    总结:这篇文章基于angular官方文档,从angular的基础,加入一些控制,和后台交互以及创建组件四个方面简单的介绍了angular。目的在于对angular有一个初步的比较全面的认识。因为刚开始接触,说的可能有点片面,也不能很好的做一个系统的总结,后期再慢慢补充,不足之处,欢迎提出!

  • 相关阅读:
    17.1.2.1 Advantages and Disadvantages of Statement-Based and Row-Based Replication
    17.1.2 Replication Formats
    Setting the Master Configuration on the Slave
    17.1.1.9 Introducing Additional Slaves to an Existing Replication Environment
    17.1.1.8 Setting Up Replication with Existing Data
    17.1.1.7 Setting Up Replication with New Master and Slaves
    17.1.1.6 Creating a Data Snapshot Using Raw Data Files
    列出display的值,并说明它们的作用
    CSS设置DIV居中
    CSS选择符有哪些?哪些属性可以继承?优先级算法如何计算?
  • 原文地址:https://www.cnblogs.com/benxiaohai-microcosm/p/6845047.html
Copyright © 2011-2022 走看看