为了降低前端代码的数量,提高可维护性,可测试性,学习了下AngularJS,正在准备投入项目开发中。

AngularJS的概念比较多,如果面向对象方面的书理解的不透的话学习起来有些费劲,它的官方有个快速入门不错,中文版如下

http://www.ituring.com.cn/minibook/303

但除了入门外,要真实的写项目还是得把模块划分,依赖关系处理,组件间通信,文件目录安排等问题解决好才能干活。

根据这个学习目的,写了个DEMO,地址如下

http://onlytiancai.github.io/codesnip/angular-demo1.html

  1. 页面初始化时有3个苹果,3个桔子,用户可以在输入框里重新输入桔子和苹果的数量,界面会有相应的变化
  2. 定义了两个模块
    1. common是通用模块,
      1. 包含一个commonErrorMsg的directive用来显示全局的错误信息, 通过监听common.showerror事件来获取信息,并让字体显示为红色
    2. myApp是整个单页面应用的模块,
      1. 包含inputCtrl, statusCtrl两个controller
      2. 包含fruits, orange, apple三个directive
      3. 包含range的filter
      4. 包含fruitsService的service
  3. 总体依赖关系如下
    1. myApp依赖common
    2. fruits, inputCtrl, statusCtrl都依赖fruitsService
    3. inputCtrl通过事件隐含依赖common
    4. 总体来说上层module依赖底层module,上层controller依赖底层service
  4. fruits是一个自定义的directive,用来显示所有水果
    1. transclude=True表示它的子元素也受它管理,比如里面的时苹果和桔子
    2. 该directive要和inputCtrl进行通信,以便动态更改水果的数量, 所以它和inputCtrl共同依赖fruitsService,并通过fruitsService的事件进行通信。
  5. 事件基本是全局的,所以定义事件时尽量有个命名空间, 如common.showerror, fruitsService.updated
  6. orange和apple是两个很普通的directive,其中apple还掩饰了directive里如何处理自身的UI事件
  7. statusCtrl就监听fruitsService.updated事件,并更新自己的状态
  8. inputCtrl里watch自身UI里的两个ng-model,适时调用fruitsService的相关方法
    1. 如果界面输入太大的数字,会向common.showerror发送消息,以在界面上提示给用户 这里没有用ng-form自带的验证就是为了演示模块间如何通信
  9. range的filter是弥补ng-repeat的不足,让它支持类似 x in range(10)的形式
  10. fruitsService纯粹是为了directive之间或controller之间通信和共享数据所设计

HTML代码

<!doctype html>
<html ng-app="myApp">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="angular.js"></script>
<script src="angular-demo1.js" charset="utf-8"></script>
<title>AngularJS Demo</title>
</head>
<body>
<p common:error_msg></p>
<p ng-controller="statusCtrl">一共有{{apple_count}}个苹果,{{orange_count}}个桔子。</p>
<fruits>
<apple ng-repeat="n in [] | range:apple_count"></apple>
<orange ng-repeat="n in [] | range:orange_count"></orange>
</fruits>
<p ng-controller="inputCtrl">请输入
<input type="text" ng-model="apple_count" />个苹果,
<input type="text" ng-model="orange_count" />个桔子
</p>
</body>
</html>

js代码

angular.module('common', []);
angular.module('common').directive('commonErrorMsg', function(){
return {
restrict: "A",
controller: function ($scope, $element, $attrs) {
$element.css('color', 'red');
$scope.$on('common.showerror', function (ev, msg) {
$element.html(msg);
});
}
}
}); var myApp = angular.module('myApp', ['common']);
myApp.directive('fruits', function(fruitsService) {
return {
restrict: "E",
transclude: true,
replace: true,
template: '<ul ng-transclude></ul>',
controller: function ($scope, $element, $attrs) {
$scope.$on('fruitsService.updated', function () {
$scope.apple_count = fruitsService.apple_count;
$scope.orange_count = fruitsService.orange_count;
});
}
}
})
.directive('orange', function() {
return {
restrict: "E",
template: '<li>桔子</li>'
}
})
.directive('apple', function() {
return {
restrict: "E",
template: '<li><a ng-click="show()" href="#">苹果</a></li>',
link: function(scope, element, attrs) {
scope.show = function(){
alert('我是一个苹果');
};
}
}
})
.controller('statusCtrl', function($scope, fruitsService) {
$scope.$on('fruitsService.updated', function () {
$scope.apple_count = fruitsService.apple_count;
$scope.orange_count = fruitsService.orange_count;
});
})
.controller('inputCtrl', function($scope, fruitsService, $rootScope) {
$scope.$watch('apple_count', function (newVal, oldVal, $scope) {
if (newVal > 10){
$rootScope.$emit('common.showerror', '苹果数量太多了');
}else{
fruitsService.set_apple_count(newVal);
}
}, true);
$scope.$watch('orange_count', function (newVal, oldVal, $scope) {
if (newVal > 10){
$rootScope.$emit('common.showerror', '桔子数量太多了');
}else{
fruitsService.set_orange_count(newVal);
}
}, true);
fruitsService.set_apple_count(3);
fruitsService.set_orange_count(2);
})
.filter('range', function() {
return function(input, total) {
total = parseInt(total);
for (var i=0; i<total; i++)
input.push(i);
return input;
};
})
.service('fruitsService', function ($rootScope) {
this.set_apple_count = function (apple_count) {
this.apple_count = apple_count;
$rootScope.$broadcast('fruitsService.updated');
};
this.set_orange_count = function (orange_count) {
this.orange_count = orange_count;
$rootScope.$broadcast('fruitsService.updated');
};
});

下面这篇帖子也很好,关于如何用AngularJS开发大型项目的。

如何组织大型JavaScript应用中的代码?

蛙蛙推荐:AngularJS学习笔记的更多相关文章

  1. AngularJs学习笔记--Guide教程系列文章索引

    在很久很久以前,一位前辈向我推荐AngularJs.但当时我没有好好学习,仅仅是讲文档浏览了一次.后来觉醒了……于是下定决心好好理解这系列的文档,并意译出来(英文水平不足……不能说是翻译,有些实在是看 ...

  2. AngularJs学习笔记--bootstrap

    AngularJs学习笔记系列第一篇,希望我可以坚持写下去.本文内容主要来自 http://docs.angularjs.org/guide/ 文档的内容,但也加入些许自己的理解与尝试结果. 一.总括 ...

  3. AngularJS学习笔记2——AngularJS的初始化

    本文主要介绍AngularJS的自动初始化以及在必要的适合如何手动初始化. Angular <script> Tag 下面通过一小段代码来介绍推荐的自动初始化过程: <!doctyp ...

  4. AngularJs学习笔记--Modules

    原版地址:http://code.angularjs.org/1.0.2/docs/guide/module 一.什么是Module? 很多应用都有一个用于初始化.加载(wires是这个意思吗?)和启 ...

  5. AngularJs学习笔记--Understanding the Model Component

    原版地址:http://docs.angularjs.org/guide/dev_guide.mvc.understanding_model 在angular文档讨论的上下文中,术语“model”可以 ...

  6. AngularJs学习笔记--Forms

    原版地址:http://code.angularjs.org/1.0.2/docs/guide/forms 控件(input.select.textarea)是用户输入数据的一种方式.Form(表单) ...

  7. AngularJs学习笔记--expression

    原版地址:http://code.angularjs.org/1.0.2/docs/guide/expression 表达式(Expressions)是类Javascript的代码片段,通常放置在绑定 ...

  8. AngularJs学习笔记--directive

    原版地址:http://code.angularjs.org/1.0.2/docs/guide/directive Directive是教HTML玩一些新把戏的途径.在DOM编译期间,directiv ...

  9. AngularJs学习笔记--html compiler

    原文再续,书接上回...依旧参考http://code.angularjs.org/1.0.2/docs/guide/compiler 一.总括 Angular的HTML compiler允许开发者自 ...

  10. AngularJs学习笔记--concepts(概念)

    原版地址:http://code.angularjs.org/1.0.2/docs/guide/concepts 继续.. 一.总括 本文主要是angular组件(components)的概览,并说明 ...

随机推荐

  1. orm获取关联表里的属性值

    ORM——关系对象模型 laravel中的Eloquent ORM用于和数据表互动,其中每个数据库表会和一个对应的「模型」互动,想要了解请查看官方文档或自行百度.获取关联表里的属性值代码如下: /** ...

  2. CSharp任何可比较的数据类型(大小比较泛型实现方法)封装

    /// <summary> /// 判定A等于B(A.CompareTo(B)==0) /// </summary> /// <typeparam name=" ...

  3. Iscroll解析

    做了一些移动端的产品,发现一些滚动效果很多会使用 iscroll 作为底层库(如阿里小蜜).iscroll 的文档已经好久没更新了,而且比较简单,经常需要直接读源码.这里写一篇总结,作为对 iscro ...

  4. 【SQLServer】“无法对数据库’XXX’ 执行删除,因为它正用于复制”的解决方法

    警告: 一个或多个现有列的 ANSI_PADDING 设置为 "off",将以 ANSI_PADDING 为 "on" 的设置重新创建 [SQLServer]& ...

  5. js高级应用

    特别板块:js跨域请求Tomcat6.tomcat7 跨域设置(包含html5 的CORS) 需要下载两个jar文件,cors-filter-1.7.jar,Java-property-utils-1 ...

  6. React阶段开发总结

    这次独立编写了React页面主要是数据切换.点击不同的按钮,Ajax请求不同的后台数据.数据驱动表格内容的显示.使用React组件开发. 开发中获得下面的心得: 1.后台给的地址早一点添加路由(写好数 ...

  7. win10 EFI装ubuntu14.04双系统 及初始配置

    这次第二次装ubuntu系统了,第一次是在win7下安装的,到了win10,由于用了efi,跟win7的安装方法不太相同,相同点有: 1.仍然可以用u盘启动,我用的是UltroISO这个软件. 2.装 ...

  8. python day2 字符串的方法

    1.首字母大写 name = "wuyuchao"result = name.capitalize()print(result)返回 Wuyuchao--------------- ...

  9. Linux的phpstudy mysql登录

    使用绝对路径登录 /phpStudy/mysql/bin/mysql -uroot -p; 设置远程登录密码 GRANT ALL PRIVILEGES ON *.* TO 'itoffice'@'%' ...

  10. IIS处理并发请求时出现的问题及解决

    一个ASP.NET项目在部署到生产环境时,当用户并发量达到200左右时,IIS出现了明显的请求排队现象,发送的请求都进入等待,无法及时响 应,系统基本处于不可用状态.因经验不足,花了很多时间精力解决这 ...