前言:记得三月份时下定决心说每天要更新一篇博客,学习点新东西,实践下来发现太不现实,生活中的事情很多,再喜欢也不能让它一件占据生活的全部吧,所以呢,以后顺其自然吧。之前有一篇'初识 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 的,其次,应该引入资源文件。它是通过各种指令来实现动态的,因此,第三个步骤就是学习各种指令。上面代码中我们用到了一个 ng-model 它将表单和模型联系在一起,能够在应用中'瞬间'获得表单输入的内容。比如,上面的代码,你在表单中输入的内容会立刻出现在 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()。
事件调用。
- //定义控制器的方法archive,显示清单库中所有还未完成的事情。
- todoList.archive = function() {
- var oldTodos = todoList.todos;
- todoList.todos = [];
- angular.forEach(oldTodos,
- function(todo) {
- if (!todo.done) todoList.todos.push(todo); //如果事件未完成,则加入事件清单里面;
- });
- };
js 代码:
- 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 后台。
先看代码:
首页,主要加载资源文件和提供显示视图的容器:
- <!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类,当输入不合法时-->
- <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
- //定义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() {
- 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();
- }
- };
- $routeProvider
- /**
- * '/'当URL是/的时候,将会加载List.html到view里,同时和ProjectListController相关联,
- * 通过阅读路由定义,你可以立即得到一个关于APP结构的概览。
- * **/
- .when('/', {
- /**
- * controller定义一个controller function可以和使用ng-congroller的dom元素关联
- * 或者和一个view template通过在路由配置里面指定从而实现关联。
- * **/
- controller: 'ProjectListController as projectList',
- templateUrl: 'list.html',
- resolve: resolveProjects
- })
- /**
- * 这个路由定义我们使用了双引号,我们可以通过双引号来让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要放置组件的元素,调用组件时传入。
- varpanes = $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: '' +
- '
- ' +
- // ng-class="{active:pane.selected}"我们创建active类名,来为处于激活状态的tab设置样式。'
- ' +
- '{{pane.title}}' +
- '
- ' +
- '' +// ng-transclude标记tabs的内容将会放置在哪里'' +
- '',
- // 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: '' +
- '',//将替换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 有一个初步的比较全面的认识。因为刚开始接触,说的可能有点片面,后期再慢慢补充,不足之处,欢迎提出!
来源: http://www.cnblogs.com/benxiaohai-microcosm/p/6845047.html