AngularJS实践

什么是AngularJS

AngularJS的核心理念是什么? 在我看来,Angualr的核心思想是:Template + Scope => HTML, Template就是各种可以复用的模板,Scope就是数据.

WEB前端原本是DOM构成一个树形结构,然后数据杂乱分布. 开发者用JQuery之类的工具在DOM上添加各种各样的数据(data, trigger, listener)等.当网页的结构复杂起来之后,各种数据之间的关联错综复杂,到最后几乎没有人可以说清楚这个庞然大物里存在多少关联. 复杂的WEB应用里有大量同类型的节点,也导致JQuery里的$("#id")到处存在,维护性极差.

AngularJS从另外一个角度来解决,将数据组织成树状结构,每一个数据节点绑定对应的模板之后就渲染出对应的HTML. 所有的数据,包括函数,触发器都绑定在这棵树上, 每一个节点的渲染过程只跟该节点上的数据以及绑定的模板有关,需要协调的关系只能通过这棵树向上追溯. 比如两个模块需要共享一个用户登录状态时,可以将用户状态定义在两个元素上节点的共同祖先节点上,这样生成两个元素节点时都引用祖先的数据,就可以生成统一的HTML了.

这是从上往下生成HTML的过程,那么如果祖先节点上的状态发生了变化,怎么让子孙节点也同步变化呢. AngularJS提供了一个检查机制, 模板是不会变化的,而HTML的生成只与模板和数据相关. 因此AngularJS沿着数据树根节点往下检查,一旦某个数据节点发生了变化,就立刻重新渲染这个节点.

为了能及时进行检查, AngularJS绑定了WEB页面上的大部分操作, 比如按键等. 一旦有这些操作发生时, AngularJS都会开始脏检查, 这样可以确保页面的不断更新. 当然这一切是建立在现在浏览器处理能力越来越强的基础上的.

AngularJS与JQuery

AngularJS也需要操作DOM,因此AngularJS有一个JQuery的子集JQLite来做DOM操作. 但AngularJS的理念是模块化和封闭化, 每一个节点的渲染封闭在该节点的DATA和Template内部, 只能通过父节点了解外部变化. 这个与JQuery那种完全扁平的结构是冲突的, 使用JQuery,我们可以在随意的位置修改HTML上任意一个节点. 这种方便性就是导致最后页面无法维护的原因.

正因为这个理念的原因, AngularJS和JQuery其实是最好不要共存的. 在使用AngularJS的很多时候我们都会有忍不住拿出JQuery来的冲动, 明明看起来很容易完成的任务, 被AngularJS封装起来后仿佛变得复杂了很多. 这个时候更建议大家重新看一下自己的设计是否需要调整. AngularJS是一个全局的理念, 不是可以一半JQuery一半AngularJS (当然有些大神能够很好的将项目划分开, 也就尽信书不如无书了, 这个当然没有绝对的方案).

Directive的compile, link

Angular中controller是用来将view上的操作与实际业务逻辑挂钩,如果需要对dom进行操作时,directive才是合适的选择。directive中有两个非常重要的概念:compile和link

  • compile

    compile是一个预处理过程,directive在compile是与实际状态无关的,compile的目的就是为了得到最终的link函数。
  • link

    link函数负责在得到具体的scope之后渲染出最终的HTML页面。

常见问题

一些技巧

Server端初始化页面参数

我们经常会遇到的问题是需要从Server得到整个页面的一些初始化条件,然后再用AngularJS在页面端运行整个App。 有一个解决方案是在页面端通过Ajax去Server请求。不过既然整个页面都是从Server请求来的,这个Ajax请求未免有点多余。

这里提供一个解决方案,利用页面渲染过程在页面上写入启动参数。

我的实际做法如下:

在页面模板上写一个angular service:(我这里用的是Jade渲染引擎,读者只关注里面的js code就好)

    script.
var serverInit = angular.module("serverInit", []);
serverInit.factory("serverParams", function(){
var params = !{JSON.stringify(serverParams)};
return params;
});

然后在server端渲染时给出参数:

	res.render('page', {serverParams : {
Id : "51955"
}});

这样在页面端我就可以使用这个初始化参数了

    var app = angular.module("testApp", ['serverInit']);
app.controller("testController", function(serverParams){
var id = serverParams.Id;
}

Angular Mocks测试时不拦截Http请求

在测试Angular程序时,我们经常会使用到AngularMocks库,这个库会用$httpBackend拦截被测试代码中的$http请求,这样可以测试代码是否如预期发送出了http请求,并且返回伪造的结果。

但如果我们不需要请求被拦截,而是需要请求发送到真实Server怎么办?StackOverflow上有一个网友给出了一个精彩的方案:

首先在测试代码文件中写一个新的angular module。

	angular.module('httpReal', ['ng'])
.config(['$provide', function($provide) {
$provide.decorator('$httpBackend', function() {
return angular.injector(['ng']).get('$httpBackend');
});
}])
.service('httpReal', ['$rootScope', function($rootScope) {
this.submit = function() {
$rootScope.$digest();
};
}]);

然后在需要测试代码中注入httpReal Service, 这个Service会将真正的$httpBackend替换回来!这样angularMocks的拦截功能就无效了。

	describe('my service', function() {
var myService, httpReal; beforeEach(module('myModule', 'httpReal')); beforeEach(inject(function( _myService_, _httpReal_ ) {
myService = _myService_;
httpReal = _httpReal_;
})); it('should return valid data', function(done) {
myService.remoteCall().then(
function(data) {
expect(data).toBeDefined();
done();
}, function(error) {
expect(false).toBeTruthy();
done();
}); httpReal.submit();
});
});

注意这个submit(),因为在AngularJS中,使用了$q来返回promise,而promise的触发是需要在$scope做脏检查的时候做的,而在UnitTest需要手动调用一次$digest去触发。

AngularJS的思考的更多相关文章

  1. AngularJS 动画总结

    对读过的几篇文章的总结,尽量保证逻辑性,不断补充.精简.更正. 后面会列出参考文章地址,方便以后取用.感谢各位作者以及翻译者. AngularJS 动画思考 一.如何使用 1)我们需要构建什么 2)如 ...

  2. 用angular来思考问题How do I “think in AngularJS” if I have a jQuery background?

    [翻译]How do I “think in AngularJS” if I have a jQuery background? 1. 不要先设计页面,然后再使用DOM操作来改变它的展现 在jQuer ...

  3. 具有jQuery背景的程序员如何转换为AngularJS思考模式(译)

    最近一直在研究angularjs,最大的感受就是它和之前的jQuery以及基于jQuery的各种库设计理念完全不同,如果不能认识到这点而对于之前做jQuery开发的程序员,去直接学习angularjs ...

  4. 对于angularJS的一点思考

    已经找好工作近两周了,入职基本上还算顺利,自己两年来的挑灯夜战也算是有了收获,于是这两周基本上是按部就班的工作,没有学习什么新技术.在上个公司的时候,同事在项目中使用angularJs,之前他也没有接 ...

  5. angularjs实现 checkbox全选、反选的思考

    之前做了一周的打酱油测试,其实感觉其实测试也是上辈子折翼的天使. 好长时间没写代码,感觉好多都不会了. 感谢这周没有单休,我能看熬夜看奥运了.我能有时间出去看个电影,我能有时间出去逛个商城,我能有时间 ...

  6. angularJs 使用中遇到的问题小结【二:购物车引起的问题思考】

    问题描述 :购物车引起的问题思考 业务逻辑是这样的:我商品加入购物车后,——>点击购物车图标——>进入订单列表(这里的数据只有首次会加载服务器数据,后面就不会执行控制器的方法了,这里的跳转 ...

  7. 关于AngularJS与其他前端框架混合使用的思考

    AngularJS 是一个为动态WEB应用设计的结构框架,拥有双向数据绑定,模板,MVVM,依赖注入,指令5大优点,Angular最有诱惑力的就是数据绑定功能,使用MVC模式进行开发,Angular在 ...

  8. AngularJS track by $index引起的思考

    今天写了一段程序,只是一个简答的table数据绑定,但是绑定select的数据之后,发现ng-change事件失去了效果,不知道什么原因. 主要用到的代码如下: <div id="ri ...

  9. MVVM大比拼之AngularJS源码精析

    MVVM大比拼之AngularJS源码精析 简介 AngularJS的学习资源已经非常非常多了,AngularJS基础请直接看官网文档.这里推荐几个深度学习的资料: AngularJS学习笔记 作者: ...

随机推荐

  1. 《转》最受欢迎的ASP.NET的CMS下载

    1. Umbraco 项目地址 | 下载 Umbraco是一个开放源码的CMS内容管理系统,基于asp.net建立,使用mssql进行存储数据. 使用Umbraco ,设计师能创造出有效的XHTML标 ...

  2. mysql数据库如何设置表名大小写不敏感?

    转自:https://blog.csdn.net/iefreer/article/details/8313839 在跨平台的程序设计中要注意到mysql的一些系统变量在windows和linux上的缺 ...

  3. Less-mixin判断(守卫)二

    mixin卫士--判断 或与且语法 且:()and() 或:(),() --且 examlpe: .test(@a) when (isNumber(@a)) and (@a>=5){ font- ...

  4. 高性能Web开发系列

    1. 高性能WEB开发基础 http://www.uml.org.cn/net/201404225.asp 2. 高性能WEB开发进阶(上) http://www.uml.org.cn/net/201 ...

  5. 4.php奇葩的地方,反引号``

    今天我发现我从来没打过这外符号 ` 就是键盘的左上方, 1的左边不需要组合键, 直接按下即可.... 刚开始我还一直在找没找到.....百度一下.才知道

  6. 手机APP卸载原因 不会卸载

  7. gitlab 阿里邮箱配置

    gitlab 阿里邮箱配置 # gitlab_rails['smtp_user_name'] = "smtp user"# gitlab_rails['smtp_password' ...

  8. mysql聚合函数操作

    1.mysql对中文进行排序 注:是用convert函数用gb2312编码转换 SELECT * FROM 表名 ORDER BY CONVERT(字段名 USING gb2312 ) ASC;

  9. pandas(六)读写文本格式的数据

    pandas提供的将表格型数据读取为DataFrame对象的函数. 函数 说明 read_csv 从文件.URL.文件型对象中加载带分隔符的数据.默认分隔符为逗号. read_table 从文件.UR ...

  10. python16_day09【Select多路复用】

    一.select多路复用 句柄列表11, 句柄列表22, 句柄列表33 = select.select(句柄序列1, 句柄序列2, 句柄序列3, 超时时间) 参数: 可接受四个参数(前三个必须) 返回 ...