对照jQuery和AngularJS的不同思维模





Question



如果我已经熟悉了怎样使用jQuery来开发client应用。我如今打算使用AngularJS。请描写叙述一下有那些思维模式方面的东西须要转变吗?以下是举出一些详细的问题。用来帮助你回答我的这个问题:



我应该以何种不同的方式来架构和设计clientweb应用?最大的不同点是什么?

我应该停止使用哪些东西;又应该開始使用哪些东西来替代?

服务端有没有什么须要考虑或者说须要约束的地方?







1.不要预先设计页面,然后再用DOM操作去改动它



在jQuery里面,你会先设计好一个页面,然后再让它变成动态的。这是由于jQuery本身就是以混合使用的思路来设计的。基于这个简单的前提,jQuery眼下已经变得臃肿不堪。



可是在AngularJS的世界中,你心中首先必须有总体架构。然后从零開始构建应用。

而不是一開始的时候就去想:“我已经有了这样一块DOM结构,我想让它做×××”,你必须首先思考你究竟要完毕什么功能,然后再開始动手。然后再设计你的应用,最后再去设计你的视图。

2.不要混合使用jQuery和AngularJS



类似地,不要一開始就抱有这种想法:jQuery能够实现X、Y和Z,所以我仅仅要在上面再覆盖一层AngularJS,把模型和控制器加上就可以。

当你刚開始使用AngularJS的时候,这种想法实在诱人,这也是为什么我总是建议AngularJS新手彻底抛弃jQuery的原因。直到他们习惯了以“Angular风格”去做事为止。



在这里,以及在邮件列表里面,我看到过非常多这样的精心设计的解决方式,当中包括150或者200行代码的jQuery插件。然后他们再用一大堆回调函 数和$apply把这些插件粘到AngularJS上。这样的做法非常复杂并且令人困惑不已;可是。他们终于竟然能把这货弄跑起来了!这里的问题在于。在大
多数情况下,仅仅须要非常少的AngularJS代码就能够把这些jQuery插件重写一遍。然后全部事情都会突然变得简洁明了起来。



底线是:在解决这个问题的过程中。首先“Think in AngularJS”(以AnguarJS的方式思考问题)。假设你想不到解决方式。请求助于社区;假设在尝试了全部这些方法之后还找不到简单的解决方式,然后再求助于jQuery。可是,不要让jQuery变成绊脚石。否则你永远无法真正掌握AngularJS。



3.保持以架构的角度思考



首先要明白一点。单页面应用是一种应用,它们不是web页面。所以,我们须要像服务端开发人员那样去思考,而不是像client开发人员那样思考。我们必须思考怎样把我们的应用切分成独立的、可扩展的、可測试的组件。



那么,你怎么才干做到这一点呢?你应该怎样以AngularJS的方式思考问题呢?以下是一些主要的原则,与jQuery做个对照。



如果有一个叫做“官方记录”(official record)的视图



在jQuery里面。我们会用编程的方式来改动视图。我们会像以下这样用ul标签来定义一个下拉列表:



<ul class="main-menu">

    <li class="active">

        <a href="#/home">Home</a>

    </li>

    <li>

        <a href="#/menu1">Menu 1</a>

        <ul>

            <li><a href="#/sm1">Submenu 1</a></li>

            <li><a href="#/sm2">Submenu 2</a></li>

            <li><a href="#/sm3">Submenu 3</a></li>

        </ul>

    </li>

    <li>

        <a href="#/home">Menu 2</a>

    </li>

</ul>



在jQuery里面。我们的应用逻辑中会像以下这行代码一样来创建这个下拉列表:



$('.main-menu').dropdownMenu();



假设我们只看视图代码,我们无法立马发现它有什么功能。对于小型的应用来说,这样做还算能够。可是对于大型应用来说。非常快就会变得混乱并难以维护。



然而。在AngularJS中,视图是一种功能,它是基于视图的“官方记录”。我们的ul声明看起来就像以下这样:



<ul class="main-menu" dropdown-menu>

    ...

</ul>



两种实现方式的效果全然同样,可是在AngularJS的版本号中。每个看到模板的人都知道它在做什么。 无论什么时候开发团队有新人进来,她看到这样的代码之后就会马上明确,存在一个叫做dropdownMenu的指令,这个指令负责操控这个视图。

她凭直觉就能够知道答案,而没有必要查看不论什么代码。视图本身已经告诉了我们这里会发生什么。这样就更加清晰了。



AngularJS新手常常会问这种问题:我怎么才干找出某种类型的全部超链接。然后在上面加上指令呢?我们会这样回答他:你不应该这么做。

然后 他总是一副惊呆了样子。你不应该这么做的原因是:这是一种半jQuery半AngularJs式的思维方式,这不科学。

用这种方式思考问题永远得不到非常好
的结果。你看到的应该是“官方记录”。

除了指令之外(不仅仅包含下面代码),你永远、永远、永远不应该去改动DOM。同一时候,指令会用在视图上,这样一来思路就清晰了。



记住:不要先设计,然后编写标签。

你必须先架构。然后去设计。



数据绑定



到眼下为止。这是AngularJS最赞的特性。利用这一特性能够省掉我在上一小节中提到的大量DOM操作代码。

AngularJS会自己主动为你刷新视图。所以不须要你自己去做这件事!

在jQuery中,我们会响应事件然后刷新页面内容。

示比例如以下:



$.ajax({

  url: '/myEndpoint.json',

  success: function ( data, status ) {

    $('ul#log').append('<li>Data Received!</li>');

  }

});



相应的视图代码例如以下:



<ul class="messages" id="log">

</ul>



这样的方式除了会把注意点混在一起之外,还有我在前面所提到的思维模式问题。可是。更加重要的一点是。这样做我们必须手动引用并更新DOM节点。

同 时,假设我们想删掉一个log对象。我们必须针对DOM又一次进行编码。这样一来我们怎样脱离DOM来測试这些逻辑呢?同一时候。假设我们要改动显示效果又应该
怎么做呢?



这样有点儿乱,代码既琐碎又脆弱。可是在AngularJS中,我们能够这样做:



$http( '/myEndpoint.json' ).then( function ( response ) {

    $scope.log.push( { msg: 'Data Received!' } );

});



然后我们的视图代码是这种:



<ul class="messages">

    <li ng-repeat="entry in log">{{ entry.msg }}</li>

</ul>



对于上面所提的删除log对象这个问题,我们能够把视图写成这样:



<div class="messages">

    <div class="alert" ng-repeat="entry in log">

        {{ entry.msg }}

    </div>

</div>



这里我们用Bootstrap的alert块替换了无序列表。而且我们永远不须要改动控制器代码!

同一时候更重要的是。不管何时或者何地更新了log对象,视图都会自己主动**刷新。高贵优雅!



尽管我没有在这里展示,事实上数据绑定操作是双向的。所以,在视图中也能够编辑log信息。仅仅要这样做就可以:<input ng-model="entry.log"/>。

另外还有很多其它惊喜。

区分数据模型层



在jQuery中。DOM有类似数据模型的意味。可是在AngularJS中。我们有一个独立的数据模型层,我们能够依照自己的想法管理它。它和视 图层全然独立。对于前面样例中的数据绑定操作来说,这一点非常实用,而且保持了注意点分离的原则,同一时候还能够引入更强的測试功能。在其他非常多解答中都提到了
这一点,所以这里我就不再赘述了。

注意点分离



以上全部一切都是为了实现这样一个远大的目标:让你的注意点保持分离。你的视图的角色是展示“官方记录”所能进行的全部操作(绝大部分);你的数据 模型用来代表你的数据;你另一个service层用来运行可复用的任务;你进行DOM操作并把指令混入到视图中;最后你再用controller把全部
东西粘到一起。

在其他非常多回复里面都提到了这一点。我唯一想要补充的一点是关于測试方面,在以下的小节中我会来讨论它。

依赖注入



用来帮助我们实现注意点分离的特性就是依赖注入。假设你是从服务端语言转过来的(比如从Java或者PHP),你可能对这个概念已经相当熟悉,可是假设你是一个前端仔。从jQuery转过来的,你可能会认为这样的概念非常愚蠢、非常多余、并且非常装逼。

但事实并不是如此。



从大的层面上讲,DI意味着你能够自由地声明组件,然后在其他组件中。你能够请求所声明组件的实例。然后你就能够获得它。你没有必要知道载入顺序、文件路径。以及诸如此类的东西。

这样的概念的强大能量可能不是那么显而易见。这里我仅仅举一个(通用的)样例:測试。



例如说在我们的应用中。依据应用的状态,我们须要通过一个REST API请求一个服务端的存储实现,以及本地的存储实现。当对我们的controller进行測试的时候,我们并不想和服务端进行通讯,毕竟我们正在測试的是controller而不是其他东西。我们可以只加入一个虚拟的同名service作为前面所说的自己定义组件。然后注射器将会保证controller可以自己主动获得这个虚拟的服务。我们的controller不会知道它们之间有什么不同,也没有必要知道。

关于測试再多说一点...



4.測试驱动开发---永远



这里的内容是关于架构方面的,实际上应该属于第三小节,可是这块内容极其重要,所以我把它独立成了一个单独的小节。

在你所见过、用过,或者写过的全部jQuery插件中,它们有多少个带有完整的測试用例?不是非常多,由于jQuery不是太鸟这个原则。可是AngularJS非常看重这一点。



在jQuery中,唯一可以进行測试的方式一般是在一个sample/demo页面上创建独立的组件,通过这个页面我们可以进行DOM操作相关的測 试。所以,这样一来我们必须独立开发一个组件。然后再把它集成到我们的应用中去。好麻烦!

在使用jQuery进行开发的时候。消耗的时间太多了,这是由于
我们选择了迭代的方式。而不是选择測试驱动开发的方式。如此一来。谁又能责备我们呢?



可是。在AngularJS中。因为我们分离了注意点,所以我们能够用迭代的方式进行測试驱动开发!

例如,例如说我们须要一个超级简单的指令,用来在菜单中显示当前的路由是什么。我们能够这样在视图中声明所须要的东西:



<a href="/hello" when-active>Hello</a>



好,如今我们来编写一个单元測试:



it( 'should add "active" when the route changes', inject(function() {

    var elm = $compile( '<a href="/hello" when-active>Hello</a>' )( $scope );



    $location.path('/not-matching');

    expect( elm.hasClass('active') ).toBeFalsey();



    $location.path( '/hello' );

    expect( elm.hasClass('active') ).toBeTruthy();

}));



我们执行这个单元測试,确认它是否会失败。然后我们再来编写指令:



.directive( 'whenActive', function ( $location ) {

    return {

        scope: true,

        link: function ( scope, element, attrs ) {

            scope.$on( '$routeChangeSuccess', function () {

                if ( $location.path() == element.attr( 'href' ) ) {

                    element.addClass( 'active' );

                }

                else {

                    element.removeClass( 'active' );

                }

            });

        }

    };

});



如今,我们的測试执行通过了,而且菜单的行为符合了我们的预期。这样一来。我们的开发既是可迭代的,也是測试驱动的。

碉堡了。



5.从概念上说,指令并不是打包好的jQuery



你常常会听到“仅仅能在指令中操作DOM”之类的言论。这是必须的。

请谨慎对待这一原则。

我们再来略微深入一点...



有一些指令仅仅是用来装饰一下视图里面已经存在的内容(想想ngClass),有时候也会直接进行一些DOM操作,然后就没有然后了。

可是,像 “widget”(小组件)这样带有模板的指令。它相同须要遵守注意点分离的原则。也就是说,模板自身相同须要保持非常强的独立性,独立于link和
controller函数的详细实现。



AngularJS内置了完整的工具,让实现这一点非常easy;我们能够使用ngClass指令来动态更新CSS样式类;ngBind能够用来做双向 数据绑定;ngShow和ngHide能够以编程的方式来显示或者隐藏元素;诸如此类还有非常多。我们也能够导入我们自己所编写的指令。换句话说,我们能够
实现各种绚丽的效果而不须要进行DOM操作。进行的DOM操作越少,指令測试起来就越easy、设置样式就越easy、在未来改动起来也会越easy、而且可复用性和 可分发性也会更好。



我看到非常多AngularJS新手把指令当成容纳各种jQuery代码的场所。换句话说,他们的想法是:“既然我不能在控制器里面做DOM操作。那我就把DOM操作相关的代码放到指令里面好了”。

这样的做法确实是好一些了,可是通常还是是错误的。



思考一下我们在第三小节里面所编写的logger应用。即使我们把相关的操作放到了指令里面,我们还是用一种“AngularJS的方式”来实现了 它。

它仍然没有做不论什么DOM操作。在非常多情况下DOM操作是必须的,可是这样的情况比你想象的要少得多。当你在应用里面的不论什么地方进行DOM操作之前,请问
问自己,是不是真的必需要这样做。

非常有可能存在更好的实现方式。



以下是一个小样例,用来说明我常常看到的一种模式。

我们须要一个开关型的button。(注意:这个样例的代码有点装逼,而且有点冗长。仅仅是为了用来代表更加复杂一些的样例,这些样例一般是以与此同样的方式来解决的。)



.directive( 'myDirective', function () {

    return {

        template: '<a class="btn">Toggle me!</a>',

        link: function ( scope, element, attrs ) {

            var on = false;



            $(element).click( function () {

                if ( on ) {

                    $(element).removeClass( 'active' );

                }

                else {

                    $(element).addClass( 'active' );

                }



                on = !on;

            });

        }

    };

});



这段代码里面有非常多错误的地方。



第一,jQuery从来就不是必须的。我们这里要实现的东西实际上全然不须要jQuery!



第二。即使我们已经在页面上引入了jQuery。也没有必要在这里去使用;对于没有使用jQuery的项目。我们可以简单地使用angular.element。这样一来我们的组件相同可以非常好地执行。



第三。如果这里必须使用jQuery我们的指令才干执行,jqLite(angular.element)总是会自己主动使用jQuery。如果jQuery已经载入了话!所以我们不须要使用$。我们仅仅要使用angular.element就能够了。



第四,与第三点类似,jqLite元素没有必要使用$来进行包装,传递给link函数的element已经是一个jQuery元素了!



还有第五点,这一点我们在前面的小节中没有提到。那就是我们为什么要把模板相关的内容混合在我们的代码逻辑里面?



以上指令能够重写成以下这样(即使对于很复杂的情况相同能够改写!)。改写之后代码极其简单:



.directive( 'myDirective', function () {

    return {

        scope: true,

        template: '<a class="btn" ng-class="{active: on}" ng-click="toggle()">Toggle me!</a>',

        link: function ( scope, element, attrs ) {

            scope.on = false;



            scope.toggle = function () {

                scope.on = !$scope.on;

            };

        }

    };

});



再说一次。模板相关的内容位于template中,所以你(或者你的用户)能够简单地切换它,从而能够满足不论什么必要的样式要求。同一时候永远不须要去改动代码逻辑。

可复用性---嘭!



这样改写之后还会带来其他优点。比方測试---这是必须的!不管模板里面是什么内容,指令内部的API永远不须要改动。这样一来重构就很easy了。你可以任意改动模板的内容而没有必要去理睬指令。

同一时候不管你改动了什么内容,你的測试依旧可以执行通过。



w00t!



好吧。假设指令并不是jQuery函数之类的集合,那么它们是什么呢?实际上指令是HTML扩展。

假设HTML无法做到你想实现的某件事情。你就自己编写一个指令,然后再去使用这个指令。好像它就是HTML的一部分一样。

换句话说,假设AngularJS没有内置支持某件事情,请思考一下你的团队应该怎么样去实现它,參照ngClick,ngClass等指令的做法。



小结



不要使用jQuery。

最好不要引入它。

它仅仅会拖你的后腿。当你遇到一个问题,而这个问题你知道怎样使用jQuery去解决。那么在你使用$之前, 请思考一下怎样以AngularJS的方式去解决它。假设你不知道,去问别人!

最好的解决方案十有八九不须要使用jQuery,假设你用jQuery的方
式来解决,终于会给你带来很多其它工作量。

其他相关内容:



1、OReilly的《AngularJS》已由电子工业出版社出版



http://damoqiongqiu.iteye.com/blog/1965167



2、《AngularJS》5个实例具体解释Directive(指令)机制



http://damoqiongqiu.iteye.com/blog/1917971



3、AngularJS表单基础



http://damoqiongqiu.iteye.com/blog/1920191



4、AngularJS Form 进阶:远程校验和自己定义输入项



http://damoqiongqiu.iteye.com/blog/1920993



5、AngularJS:在Windows上安装Yeoman



http://damoqiongqiu.iteye.com/blog/1885371



6、对照Angular/jQueryUI/Extjs:没有一个框架是万能的



http://damoqiongqiu.iteye.com/blog/1922004



7、使用JsTestDriver实现JavaScript单元測试



http://damoqiongqiu.iteye.com/blog/1924415



8、JavaScript单元測试系列二:将Jasmine集成到JsTestDriver



http://damoqiongqiu.iteye.com/blog/1925974

对照jQuery和AngularJS的不同思维模的更多相关文章

  1. 对比jQuery和AngularJS的不同思维模式

    jQuery是dom驱动,AngularJS是数据驱动,这里有一篇文章阐述的非常好,建议看看 本文来自StackOverFlow上How do I “think in AngularJS” if I ...

  2. 转载:Think in AngularJS:对比jQuery和AngularJS的不同思维模式(大漠穷秋)

    导言 stackoverflow上有一个人问了一个问题:如果我有jQuery背景,我应该如何切换到AngularJS的思维模式? 有一个回复非常经典,获得了两千多票. 为了让国内开发者也能领略到其中的 ...

  3. jQuery和AngularJS的区别小分析

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

  4. jQuery和AngularJS的区别

    这篇文章主要介绍了jQuery和AngularJS的区别浅析,本文着重讲解一个熟悉jQuery开的程序员如何应对AngularJS中的一些编程思想的转变,需要的朋友可以参考下   最近一直在研究ang ...

  5. 玩转spring boot——结合jQuery和AngularJs

    在上篇的基础上 准备工作: 修改pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=&q ...

  6. 强强联合之jquery操作angularjs对象

    jquery是一个非常强大的js框架,angularjs是一个非常牛的前端mvc框架.虽然用其中的任何一个框架在项目中够用了,但是有时候这两个框架需要混合着用,虽然不推荐.但有时候混合用时,却非常方便 ...

  7. 体验jQuery和AngularJS的不同点以及AngularJS的迷人之处

    本篇通过jQuery和Angular两种方式来实现同一个实例,从而体验两者的不同点以及AngularJS的迷人之处. 首先当然需要引用jquery.js和angular.js文件. ■ 使用jQuer ...

  8. AngularJS应用开发思维之3:依赖注入

    找不到的API? AngularJS提供了一些功能的封装,但是当你试图通过全局对象angular去 访问这些功能时,却发现与以往遇到的库大不相同. $http 比如,在jQuery中,我们知道它的AP ...

  9. zepto/jQuery、AngularJS、React、Nuclear的演化

    写在前面 因为zepto.jQuery2.x.x和Nuclear都是为现代浏览器而出现,不兼容IE8,适合现代浏览器的web开发或者移动web/hybrid开发.每个框架类库被大量用户大规模使用都说明 ...

随机推荐

  1. 你必须要知道的几个CSS技巧

    有些经典的CSS技巧,我们还是需要记住的,这样可以节省我们大量的时间,下面零度就为大家推荐几个比较好的CSS技巧: 1.在不同页面上使用同样的导航代码 许多网页上都有导航菜单,当进入某页时,菜单上相应 ...

  2. 小项目: low版本的 员工信息程序:

    ### 附加两个文件1 user_info 和worker_info flag = False def logon(): #登录函数 global flag usr = input('Username ...

  3. [ Java ] [ Spring ] Spring 一些配置项 及 <context:annotation-config/> 專文解释说明

    節錄重點: @ Resource .@ PostConstruct.@ PreDestro.@PersistenceContext.@Required 都必須聲明相關的 bean 所以如果總是需要按照 ...

  4. JAVA使用YUI压缩CSS/JS

    前言 JS/CSS文件压缩我们经常会用到,可以在网上找在线压缩或者本地直接使用,我这里使用的是yahoo开源组件YUI Compressor.首先介绍一下YUI Compressor,它是一个用来压缩 ...

  5. Linux 关闭正在运行的程序---命令

    Ctrl + C 终止 Ctrl + D 退出 Ctrl + S 挂起 Ctrl + Q 解挂 Ctrl + Z 强制结束

  6. centos7 docker镜像源设置

    由于docker他的镜像下载地址是国外官网源需要修改 添加 Docker 加速镜像(阿里云专属) 安装/升级你的Docker客户端 推荐安装1.10.0以上版本的Docker客户端,参考文档 dock ...

  7. js29--装饰着模式

    //装饰者模式:就是在保证不改变原有对象的基础上,去扩展一些想要的方法或去求 var CarInterface = new BH.Interface('CarInterface' , ['getPri ...

  8. 为什么会出现NoSQL数据库

    为什么会出现NoSQL数据库 一.总结 一句话总结:sql不支持分布式且且有性能瓶颈且不支持分布式,不同NoSQL适合不同的场景 1."不同的NoSQL数据库只适合不同的场景"这句 ...

  9. 洛谷P3165 [CQOI2014]排序机械臂

    题目描述 为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂.它遵循一个简单的排序规则,第一次操作找到摄低的物品的位置P1,并把左起第一个至P1间的物品反序:第二次找到第二低的物品 ...

  10. C#打印日志的小技巧(转)

    https://www.cnblogs.com/jqg-aliang/p/5234206.html 打印日志的函数 开发中输出日志必不可少,在C#中输出多个不同类型参数的时候,需要连接符累加输出,很是 ...