二识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有一个初步的比较全面的认识。因为刚开始接触,说的可能有点片面,也不能很好的做一个系统的总结,后期再慢慢补充,不足之处,欢迎提出!
二识angularJS的更多相关文章
- 通过AngularJS实现前端与后台的数据对接(二)——服务(service,$http)篇
什么是服务? 服务提供了一种能在应用的整个生命周期内保持数据的方法,它能够在控制器之间进行通信,并且能保证数据的一致性. 服务是一个单例对象,在每个应用中只会被实例化一次(被$injector实例化) ...
- AngularJs之九(ending......)
今天继续angularJs,但也是最后一篇关于它的了,基础部分差不多也就这些,后续有机会再写它的提升部分. 今天要写的也是一个基础的选择列表: 一:使用ng-options,数组进行循环. <d ...
- AngularJS过滤器filter-保留小数,小数点-$filter
AngularJS 保留小数 默认是保留3位 固定的套路是 {{deom | number:4}} 意思就是保留小数点 的后四位 在渲染页面的时候 加入这儿个代码 用来精确浮点数,指定小数点 ...
- Angular企业级开发(1)-AngularJS简介
AngularJS介绍 AngularJS是一个功能完善的JavaScript前端框架,同时是基于MVC(Model-View-Controller理念的框架,使用它能够高效的开发桌面web app和 ...
- 模拟AngularJS之依赖注入
一.概述 AngularJS有一经典之处就是依赖注入,对于什么是依赖注入,熟悉spring的同学应该都非常了解了,但,对于前端而言,还是比较新颖的. 依赖注入,简而言之,就是解除硬编码,达到解偶的目的 ...
- 步入angularjs directive(指令)--点击按钮加入loading状态
今天我终于鼓起勇气写自己的博客了,激动与害怕并存,希望大家能多多批评指导,如果能够帮助大家,也希望大家点个赞!! 用angularjs 工作也有段时间了,总体感觉最有挑战性的还是指令,因为没有指令的a ...
- 玩转spring boot——结合AngularJs和JDBC
参考官方例子:http://spring.io/guides/gs/relational-data-access/ 一.项目准备 在建立mysql数据库后新建表“t_order” ; -- ----- ...
- 玩转spring boot——结合jQuery和AngularJs
在上篇的基础上 准备工作: 修改pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=&q ...
- 通过AngularJS实现前端与后台的数据对接(一)——预备工作篇
最近,笔者在做一个项目:使用AngularJS,从而实现前端与后台的数据对接.笔者这是第一次做前端与后台的数据对接的工作,因此遇到了许多问题.笔者在这些问题中,总结了一些如何实现前端与后台的数据对接的 ...
随机推荐
- 开源的C#实现WebSocket协议客户端和服务器websocket-sharp组件解析
很久没有写博客了(至少自己感觉很长时间没有写了),没办法啊,楼主也是需要生活的人啊,这段一直都在找工作什么的.(整天催我代码的人,还望多多谅解啊,我会坚持写我们的项目的,还是需要相信我的,毕竟这是一个 ...
- Java关于e.printStackTrace()介绍
public void printStackTrace()将此 throwable 及其追踪输出至标准错误流.此方法将此 Throwable 对象的堆栈跟踪输出至错误输出流,作为字段 System.e ...
- 【shell编程基础2】shell组合应用之一:重定向和逻辑
这篇主要讲下 数据的重定向,在shell脚本中有些重要的输出重定向为文件的形式输出来 逻辑方式的多个命令组合,可以很方便的进行一些判断 数据流重定向 数据流重定向:大致上的意思就是本该输出到屏幕上的数 ...
- 使用vs2015搭建Asp.net Core
准备工具 1.首先得安装vs2015 并且升级至 update3及以上 2.安装.net core sdk.附上官网下载地址 http://www.microsoft.com/net/down ...
- 现有‘abcdefghijkl’12个字符,将其所有的排列按字典序进行排序,给出任意一组排列,说出这租排列在所有排列中是第几小的
题目: 现有‘abcdefghijkl’12个字符,将其所有的排列按字典序进行排序,给出任意一组排列,说出这租排列在所有排列中是第几小的 据说这道题是百度校招的一道算法题,反正我觉得我在学校的时候很可 ...
- MySQL中字符串与数字比较的坑
公司项目代码中,某枚举字段数据库表中类型是char(1),在代码中,误以为是TINYINT,所以用数字筛选,后来发现结果不对.发现了一个现象,用数字0筛选会把所有的记录给筛选出来. 经过排查发现是在M ...
- SecureCRT中vim乱码问题
Options->Session Options,接着在Terminal->Appearance页签中设定Character encoding为Unicode (UTF-8).
- JavaWeb的国际化(17/4/8)
国际化的缺点: 因为文字不同,所以带来的排版问题一样严重,通常都是重新在写一个网站反而更加清晰,快捷 1:需要从浏览器中获取到浏览器语言(Accept-Language) 2:利用locale获取 ...
- 【知识必备】浅淡MVP在Android项目中的实战演习,让代码结构更简单~
一.写在前面 讲道理,这次是真的笔者很久都没有更新blog了,主要最近维护的框架问题也是层出不穷,而且对技术交流群的解答也让我身心疲惫,所以在这里跟关注我的人说声抱歉,没有定期给你们带来福利,那么这里 ...
- 从JDBC到hibernate再到mybatis之路
一.传统的JDBC编程 在java开发中,以前都是通过JDBC(Java Data Base Connectivity)与数据库打交道的,至少在ORM(Object Relational Mappin ...