AngularJs 与Jquery的对比分析,超详细!

闲来无事,在网上发现了一篇对比AngularJs和Jquery的文章.刚好最近本身也在研究AngularJs.特此收藏.须要的朋友能够参考.jquery

原问题:假如我熟悉利用jQuery去开发客户端应用,那么我怎么上手angularjs,可否描述下所须要的模式转变,下面这些问题可以帮助你给出一个回答:angularjs

1.在设计客户端web应用的时候有什么区别,最大的区别是什么?web

2.我应该中止使用哪些技术,同时又使用哪些技术做为替代?ajax

3.是否存在服务端须要考虑的东西或者说一些限制呢?编程

回答:json

1.不要首先设计好你的页面,而后再经过DOM操做去修改它架构

在jQuery中,你首先设计了一个page,而后再去动态修改它的内容,这是由于jQuery被设计用来进行扩展并在这个前提下大幅度地增长和修改内容,可是在angularjs中,你必须在心中先设计好你的架构,并发

从一开始,你就要摒弃“我拥有一个DOM元素而且想让它去作某件事”,代之为“我须要完成什么任务,而后接着设计你的应用,最后再去设计你的视图view层”。app

2.不要使用angularjs去扩展jQuery框架

相应地,不要存在说让jQuery去干某些事情,而后在此基础上添加angularjs的功能让它去管理model以及controller的想法。因此我通常不推荐AngularJS开发新手同时使用jQuery,至少在他们尚未适应AngularJS的开发模式以前不会去推荐这样作,可是当你真正开始适应angularjs 的方式以后,你会发觉这是一件很诱人的事情。

我曾经看到过不少开发者采用将150到200行代码的jQuery插件利用angularjs的回调以及$apply方法封装起来,这种方式使得代码看起来极其复杂,可是实际上他们让这些插件跑起来了!问题在于,在大部分状况下jQuery插件可以用angularjs进行重写,而且可能只会使用不多量的代码,同时这种重写使得代码很直观且易于理解,这显然好过于将jQuery代码直接作封装。

因此最后说,当你碰见问题的时候,首先要以angularjs的思惟进行思考,若是找不到解决方案,能够求助于社区,若是说没有人可以给出一个简单的方案,那么才考虑使用jQuery,不要让jQuery成为你的拐杖,不然你永远掌握不了AngularJS。

3.要以架构为中心进行思考

首先你要知道单页应用属于web应用,它们不是传统的多网页网站,因此咱们要同时做为一个服务端和客户端开发者的思惟进行思考,咱们须要思考如何将咱们的应用分为独立的,可扩展的以及可测试的部分。

那么接下来咱们如何采用AngularJS思惟去工做呢,如下是一些将其与jQuery对比以后的基本准则:

如下是某个应用的视图层:

在jQuery中,咱们动态地去修改这个视图,咱们使用ul去定义一个dropdown menu

复制代码代码以下:

<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中,咱们采用以下逻辑使用这个dropdownMenu

复制代码代码以下:

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


让咱们回头看看这个view,你会发现它的功能并非很直白,对于小型应用来说,这样是能够的,可是对于大型应用来说,这种方式会让人费解而且难以维护;

 

在angularjs中,这个视图其实是一项基于视图的功能,咱们能够这样来定义ul

 

复制代码代码以下:

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

 

这两种方式实际上作了一样的事情,可是在AngularJS方式下任何人看到这个视图模板就知道接下来要干什么。不管什么时候当一个新成员加入开发团队以后他都可以看到这里并发现这里有一个叫作dropdownMenu的指令去操做view,他不须要去猜测正确的答案或者审查其余的代码,这个视图就直接告诉咱们它要作什么,相比于jQuery,它更为简洁。

经常有些AngularJS新手问这样的问题:我怎么才能找到某个确切类型的全部link并在此基础上添加一个directive,可是当咱们回答了“你不该该这样去作,你这是一种半jQuery半angularjs的想法”时,他们会以为很吃惊。

问题在于他们试图在AngularJS背景下用jQuery去作某件事,这一般不是一种好的方式,在指令以外你不须要去作任何dom操做,而指令是直接内添加在视图上的,因此意图已经很明显了。记住,不要先设计好以后再去修改,而是先有架构而后在这个框架下再去设计。

数据绑定

这是到目前为止AngularJS最使人瞩目的特性了,在数据绑定方面它舍弃了对DOM的操做方式,而这一切都是由AngularJS来自动更新视图,你没必要写操做dom的代码,在jQuery中,咱们经常按照如下方式响应事件并修改视图:

 

复制代码代码以下:

$.ajax({
  url: '/myEndpoint.json',
  success: function ( data, status ) {
    $('ul#log').append('<li>Data Received!</li>');
  }
});

 

相对于这样一个视图

 

复制代码代码以下:

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

 

除了混杂的问题以外,咱们还存在我以前提到的如何代表本身意图的问题。可是更为重要的是,咱们必须人工手动去引用并更新这个DOM节点,若是咱们想删除其中一条,那么必须以编程方式去操做那个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>


在那种状况下,咱们的视图也能够这样

 

 

复制代码代码以下:

<div class="messages">
    <div class="alert" ng-repeat="entry in log">
        {{ entry.msg }}
    </div>
</div>

 

如今咱们不使用ul,而是使用Bootstrap的弹出框,可是咱们不用修改controller中的代码,更为重要的是,无论是数据如何修改,视图层也会自动随之发生变化,很是简洁!

尽管我这里不会作演示,可是你须要知道数据绑定是双向的,你能够编辑数据经过添加指令<input ng-model="entry.msg" />,此外还有不少其余的使人兴奋的地方。

区别model层

在jQuery中,DOM相似于一种model,可是在AngularJS中,咱们拥有不一样于jQuery中的model层以便咱们能够以任何咱们想要的方式去管理它,它是彻底独立于视图以外的。这种方式是有助于咱们进行数据绑定而且能够保持对分离的关注,并且能够具有更好的可测试性。

关注点分离

以上所讲都和这个整体的话题相关:让你关注分离,你的视图层显示记录,你的model层表明数据,你还有个服务层用来执行这些可复用的任务。你使用directive来执行dom操做并扩展你的视图,并将它和controller链接起来,这也就是我在其余方面提到的有关于加强可测试性的缘由。

依赖注入

帮助咱们解决关注点分离的是依赖注入(DI),若是你是一个服务端开发者(Java或者PHP),你可能已经很熟悉这个概念了,可是若是你是从事客户端开发的,你会以为这个概念可能有些多余和纯属追求时髦,可是实际上不是这样。

从广义的角度讲,DI意味着你能够自由地声明组件而后从这些组件中进行实例化,这是理所固然的。你没必要知道加载顺序,文件位置等诸如此类的事情,这种魔力不是可以当即看到,可是我会给出一个例子:测试。

咱们说在应用中,咱们须要一个依赖于应用状态和本地存储的服务用来经过一个rest API来执行服务端存储,当咱们测试咱们的controller时,咱们没必要和服务端进行通讯,毕竟只是在测试controller而已。咱们仅添加一个与咱们最初组件相同的mock服务,注入器可以确保咱们的controller得到一个虚拟的服务,controller自身没必要也不须要了解这种差别。

那么说说测试吧。

4.以测试驱动的开发

这部分是一个架构的第三部分,可是他是很重要的,以致于我须要将它放在最重要的位置。

在咱们全部见过的,用过的以及写过的jQuery插件中,有多少具备一套测试组件呢?其实并很少,这是由于jQuery在测试上不易控制,可是AngularJS却与此不一样。

在jQuery中,测试的惟一方法是使用一个demo页去建立一个独立组件来使得咱们的测试能够执行dom操做。咱们接下来咱们必须开发一个独立的组件而后将它集成到咱们的应用中来,这是多不方便啊!在不少状况下,当咱们使用jQuery开发其实是作了不少重复开发而不是以测试驱动的开发,这又能怪咱们吗?

可是在AngularJS中咱们能够关注分离点,因此咱们能够作一些测试驱动的开发。例如,咱们有一个directive用来讲明在menu中咱们的当前路径,咱们能够在视图中这样声明:

复制代码代码以下:

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

 

好了,如今咱们能够写一个测试用来测试这个不存在的指令when-active了

复制代码代码以下:

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();
}));

 

咱们直接run测试用例,你会发现是失败的,这时候须要建立这个指令,以下:

 

复制代码代码以下:

.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' );
                }
            });
        }
    };
});

 


再次run这个测试用例,你会发现经过了而且菜单如请求的样子显示,咱们的开发是兼有反复性和可测试性,很是酷吧!

5.从概念上讲,指令不是打包的jQuery

你经常据说,dom操做只能在指令中,这是必须的,你必须严肃对待。

让咱们深刻讨论,

某些指令仅仅是装饰咱们的视图(例如ngClass),所以有时候直接操做dom是能够的,可是当一个指令相似于一个小物件而且拥有本身的模板,那么它应该当作一个分离的关注点,这就是说,它的模板须要和link中的执行逻辑以及其余controller函数分离开。

AngularJS拥有一整套的工具能够是这种分离更简单,使用ngClass指令,咱们能够动态地更新class,使用ngBind咱们能够进行双向数据绑定,使用ngShow和ngHide 咱们

能够采用编程的形式显示和隐藏一个元素,也包括咱们本身写的不少指令。换句话说,咱们能够不用Dom操做而完成全部工做,dom操做越少,指令越容易测试,越容易指定他们的style属性,就越容易在未来改变他们,那么他们就越容易复用和分发。

我看过不少AngularJS新手使用指令封装一大串 jQuery代码,换句话说,既然我不能在controller里面进行dom操做,那么我能够将他放在指令中,虽然这相对于直接操做dom好不少,可是任然是错误的。

看看咱们在上面的记录,即便咱们将其放在一个指令中,咱们任然须要以Angular的方式去操做它,这种方式不执行dom操做!在不少时候dom操做是须要的,可是这种状况比你想的要少得多。当咱们须要作dom操做的时候先问问本身这里是否必须这样作,这才是一种更好的方式。

下面是一个简单的例子用来代表我经常见到的一种模式,咱们须要I一个可切换的button:

复制代码代码以下:

.directive( 'myDirective', function () {
    return {
        template: '<a class="btn">Toggle me!</a>',
        link: function ( scope, element, attrs ) {
            var on = false;
 
            $(element).click( function () {
                on = !on;
                $(element).toggleClass('active', on);
            });
        }
    };
});

 

在以上例子中存在如下错误:

1.首先,jQuery是没必要要的,这里的工做彻底不须要jQuery!

2.第二,即便咱们已经在页面中引入了jquery,可是咱们没有理由去使用它,咱们可使用angular.element而咱们的组件也可以运行,即便这个项目中没有引入jQuery。

3.第三,假设jquery是须要的在咱们的指令中,咱们可使用jqLite去进行替代,只要引入jQuery便可,因此咱们没必要使用$而是使用angular.element;

4.第四,和第三点联系很紧密,jqLite元素没必要使用$包裹起来,element元素传递到link函数中已是一个jQuery对象了;

5.第五,咱们以前已经说过,为何不将咱们的模板和逻辑混合起来呢?

以上指令能够按照以下方式来重写,即便在最复杂的状况下看起来也如此简单。

复制代码代码以下:

.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属性中,你能够很容易替换掉它的style,而逻辑根本不用发生变化,达到了彻底复用!

还有其余的好处,好比测试起来很简单,无论模板里面是什么,指令API都不会发生改变,因此重构它很简单。你能够随意屡次改变你的模板而不用改变指令,不管你怎么改变,你的测试总能经过!

因此说指令不是一堆jQuery代码的集合,好比函数等,而是HTML代码的扩展,若是HTML代码不能实现你须要的功能,你能够写一个指令去实现它,而后像使用HTML那样去使用它。

以另一种方式讲,AngularJS若是不作额外的事情,想一想咱们怎么可以使用ngClick,ngClass指令呢?

能够说AngularJs与Jquery的优点乃至设计思路各有不一样,按照个人理解.前者是先搭好房屋,再等人入驻.然后者是,须要入驻的人,带着砖瓦本身来修一栋楼.至于哪种更方便更适合你,因人而异了.

相关文章
相关标签/搜索