首頁  >  文章  >  web前端  >  如何用AngularJS程式設計思想

如何用AngularJS程式設計思想

小云云
小云云原創
2017-12-04 10:29:021428瀏覽

AngularJS是一款優秀的前端JS框架,已經被用於Google的多款產品當中。 AngularJS有著許多特性,最為核心的是:MVC、模組化、自動化雙向資料綁定、語意化標籤、依賴注入等等。本文我們主要和大家分享一下會jQuery,該如何用AngularJS編程思想。

1. 我如何對客戶端web應用進行不同方式的架構與設計?它們之間最大的差異是什麼? (譯者註:指jQuery和Angular.js)

2. 有什麼是我不該做或不該使用的;而又有什麼是我應該做或應該使用的呢?

3. 有沒有一些服務端的考量/限制呢?

我在尋找的就是一個關於jQuery和Angular.js之間的詳細的比較。 」

以下是來自 Josh David Miller  的最佳答案:

#1. 絕對不要先設計你的頁面,然後用DOM操作改變它

在jQuery中,你會先設計一個頁面,然後讓它變得動態化。中, 你必須從一開始就在腦子裡掛著架構的弦。設計你的應用, 最後才是設計你的視圖。 X,Y,Z,所以我只要在其上為模型和控制器添加Angular.js就行了。至少要在他們習慣了「angular 方式」之後。 ,然後利用一堆讓人困惑的複雜的回調和$apply與Angular.js粘合起來建立這些詳盡的解決方案;最終確實可以跑起來! Angular.js程式碼來重寫jQuery外掛即可,而這種方式會讓一切剎那間簡單明了可理解。 「Angular.js思想」去做;如果你不能想出一個方案,那麼就在社區裡詢問;如果還是沒有簡單的解決方法,那麼再請隨意使用jQuery吧。的拐杖,不然你將永遠無法真正精通Angular.js。需要有服務端開發者想法加上客戶端開發者想法。如何做到利用「angualrjs思想」呢?視圖。

<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>

當我們只是看著視圖的時候,不會立刻看出它的功能。對於小應用而言,這樣是沒問題的。但是對於大型的應用,情況就一下子變得令人困惑且難以維護。

但是在Angular.js中,檢視是基於檢視的功能的正式記錄。我們的ul是像下面這樣聲明的:

$(&#39;.main-menu&#39;).dropdownMenu();

這兩者其實做了同樣的事情,但是在Angular.js的版本中,任何看到這個模板的人都知道將要發生什麼。不論何時,開發團隊裡有任何新的開發人員加入,她可以一眼看出有一個叫做dropdownMenu的指令作用在視圖上;她根本不需要憑直覺猜測或者研究下代碼才找到正確的答案。視圖本身就告訴我們會發生什麼事了。清晰多了。

angualrjs的新手常常會問這樣一個問題: 我如何找到某一類所有的連結並且為它們添加一個指令呢?看到我們回覆的時候朋友都震驚了:壓根別去這樣做。但是勸你不要這樣做的原因是,這樣做就像是一半jQuery,一半angulrjs,而這真心很糟。這裡的問題是,開發者想在angualrjs的情境中使用jQuery方式。而這絕對不會玩得轉。視圖是正式記錄。超出指令的範圍(這點下文會談論更多),你絕不要去改變DOM。而且指令是應用在視圖中的,目的自然也一目了然。

記住:不要先設計再修飾。你必須先進行架構,然後再考慮設計。

資料綁定

這是Angular.js目前最酷的特性之一,並且秒殺我前文提到的各種需要的DOM操作。不需要你自己動手,Angular.js將自動更新你的視圖有木有!

在jQuery里, 我们响应事件并更新内容,大概是这个样子:

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

视图则看上去是这样的:

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

除了关注点混合的问题,这里同样有之前提到的表征目的的问题。更重要的是,我们不得不手动引用并更新dom节点。并且如果我们想要删除一个日志,我们不得不再次对dom编程操作。我们怎样才能抛开dom来测试逻辑呢?还有,如果我们希望改变展现呢?

真是让人凌乱。。。

但是在Angular.js中,我们可以这样做:

$http( &#39;/myEndpoint.json&#39;).then(function( response ) {
    $scope.log.push( { msg:&#39;Data Received!&#39;} );
});

我们的视图看上去是这样的:

<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>

现在,替换掉了无序列表,我们使用Bootstrap警告框。同时我们根本不需要改变控制器代码!更重要的是,不论日志何时或者如何更新,视图也会跟着改变。自动的!漂亮!

虽然我没有在这里演示出来,但是数据绑定是双向的。所以这些日志信息同样可以在视图中被编辑,就像这样:

<input ng-model= "entry.msg" />

是不是更开心了?

不同的模型层

在jQuery中,dom有点像模型。但是在angualrjs中,我们有一个分离的模型层, 而这个模型层可以让我们用任何方式管理,完全独立于视图。这对于上面说的数据绑定很有帮助, 还可以维护关注点分离,并且引入更多的可测试性。其它的答案提到了这点,所以我这里就不再赘述了。

关注点分离

以上所有的这些把我们带入了这样的主题:保持你的关注点分离。你的视图表现的像记录什么会发生(大部分情况)的正式记录;你的模型表现你的数据;你有一个服务层来执行可重用的任务;你执行dom操作并通过指令扩展你的视图;并且你用控制器来组合这些。这些同样已经在其它答案中提到,我在这里唯一还要提出的一个事情就是可测试性,我会在下文的另一节里专门讨论。

依赖注入

依赖注入是让我们实现关注点分离的方法。如果你是一个服务器端的开发者(从java到php),你可能对这个概念已经非常熟悉了,但是如果你是一个来自jQuery的客户端的朋友,那么你可能会认为这个概念是傻浅挫。但是它可不是:)

从一个更广的观点来看, 依赖注入意味着你可以非常自由的声明组件,然后你可以通过任意其它组件,呼叫一个它的实例,然后授权。

你不需要知道载入顺序,或者文件位置,或者其它类似的东西。这种强大的力量可能不会立刻显现,但是我这里会提供一个(通常)的例子:测试。

比如在我们的应用中,需要一个通过REST API,同时也依赖于应用状态,本地存储实现了服务器端存储的服务。当在我们的控制器上跑测试的时候,我们不希望与服务器端通讯-毕竟我们在测试控制器。我们能够仅仅添加一个与我们原始组件同名的mock服务,注入器将确保我们的控制器自动获取伪造对象–我们的控制器不会也不需要知道它们的区别。

那么既然提到测试……

4. 保持测试驱动的开发

这个其实是关于架构的第三节的一部分,但是这个主题非常重要,所以我需要将其提出来作为自成体系的部分。

那些你看过,用过,写过的所有jQuery插件,它们中有多少有相应的测试包?不是很多吧? 因为jQuery可不是很遵守这个规矩。但是angualrjs是。

在jQuery中, 测试的唯一方法是用示例页面来独立地创建组件,针对该页面我们的测试可以实施dom操作。于是我们就不得不分离地开发一个组件然后将其集成进我们的应用。多么不方便啊!

那么多时间啊,当我们使用jQuery开发时,我们选择使用迭代开发代替测试驱动的开发。可以谁又能怪我们呢?

但是因为我们有关注点分离,我们能够在Angular.js里反复使用测试驱动开发。举个例子,我们想要一个超简单的指令来指示在菜单中我们目前的路径是什么。我们可以在视图中这样声明我们想获取的:

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

好了,我们现在可以写个测试:

it( &#39;should add "active" when the route changes&#39;, inject(function() {
    varelm = $compile(&#39;<a href="/hello" when-active>Hello</a>&#39;)( $scope );
 
    $location.path(&#39;/not-matching&#39;);
    expect( elm.hasClass(&#39;active&#39;) ).toBeFalsey();
 
    $location.path(&#39;/hello&#39;);
    expect( elm.hasClass(&#39;active&#39;) ).toBeTruthy();
}));

我们运行测试,并确认它是失败的。那么我们来写下我们的指令:

.directive( &#39;whenActive&#39;,function( $location ) {
    return{
        scope:true,
        link:function( scope, element, attrs ) {
            scope.$on(&#39;$routeChangeSuccess&#39;,function() {
                if( $location.path() == element.attr(&#39;href&#39;) ) {
                    element.addClass(&#39;active&#39;);
                }
                else{
                    element.removeClass(&#39;active&#39;);
                }
            });
        }
    };
});

现在我们的测试通过了,并且我们的菜单按照请求运行。我们的开发是迭代并且测试驱动的,太酷了哦!

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

你会经常听到“只在指令里做dom操作”。这是必要的。请对它表示出尊重!

但是让我们谈点更深入的。。。

一些指令只是装饰那些在视图里的已有的(想想ngClass),因此有时候就直接进行dom操作,基本上都能搞定。但是如果一个指令像个“widget”并有一个模板,

那它同样要遵守关注点分离原则。也就是说,这个模板也应该与它在链接和控制器函数里的实现保持最大的独立。

Angular.js自带着一套工具让这件事变得简单; 使用ngClass我们能够动态的更新类;ngBind允许双向的数据绑定;ngShow和ngHide以编程的方式显示或隐藏一个元素;还有更多–包括我们自己写的那些。换句话说, 我们可以不用DOM操作来实现所有的酷炫的事儿。 dom操作越少,指令越容易测试,它们也更容易样式化,在未来它们也更容易改变,并且也变得更加可重用和可分发。

我看到很多Angular.js开发新手将指令当做放置一堆jQuery的地方。换句话说, 他们认为:“既然我不能在控制器里做dom操纵,那么我就把这段代码放到指令里”。当然这看上去好多了,但是通常这仍然是错的。

想一下在第三节里我们编写的日志记录。即使我们将其放到一个指令里,我们仍然希望用“anggualjs方式”来做这件事情。这仍然没有做任何dom操作!在很多情况下dom操作是必须的,但是这种情况其实比你想的少得多!在你在你的应用中到处使用dmo操作之前,问问你自己,这真的是必须的吗。可能有更好的方法呢。

这里用一个简单的例子来展示我们经常会看到的一个模式。我们需要一个切换按钮。(注意:这个例子有那么一点人为设计的技巧并且有点啰嗦,但是很多更复杂的情况其实也完全可以根据这个例子的方式来解决。)

.directive( &#39;myDirective&#39;,function() {
    return{
        template:&#39;<a class="btn">Toggle me!</a>&#39;,
        link:function( scope, element, attrs ) {
            varon =false;
 
            $(element).click(function() {
                if( on ) {
                    $(element).removeClass(&#39;active&#39;);
                }
                else{
                    $(element).addClass(&#39;active&#39;);
                }
 
                on = !on;
            });
        }
    };
});

这里有一些错误。第一,jQuery不是必须的。我们这里做的一切都不需要jQuery!第二, 即使是我们的页面上已经有jQuery,也没有理由一定要在这里使用它;我们可以简单的使用angular.element,而且就算在一个没有jQuery的项目中我们的组件仍然可以工作。第三,即使我们假设为了让这个指令工作,jQuery是必须的,如果jqury被加载,那么jqLite(angler.element)一定会使用jQuery。所以我们不需要使用$(译者注:jQuery的一个标识符号,是jQuery函数的别名)–我们可以使用angular.element。第四, 紧接第三点,jqLite元素不需要被包裹在$里–传递给link函数的element已经是一个jQuery元素!第五, 我上一节已经提过的,为什么我们要将模板混合进我们的逻辑呢?

这个指令可以更精简的重写(即时在更复杂的例子里也一样):

.directive( &#39;myDirective&#39;,function() {
    return{
        scope:true,
        template:&#39;<a class="btn" ng-class="{active: on}" ng-click="toggle()">Toggle me!</a>&#39;,
        link:function( scope, element, attrs ) {
            scope.on =false;
 
            scope.toggle =function() {
                scope.on = !$scope.on;
            };
        }
    };
});

再次强调,模板的那些代码都是在模板里的,所以你或者你的使用者能够很方便的将其换成一个符合任何需要的样式,同时逻辑不被改变。这就是重用性-赞!

当然,还有其它很多好处–比如测试 – 这很容易! 不论什么在模板中,指令的内部API绝不会被接触,所以重构就变得容易。你可以在不接触指令的情况下随意改变你的模板。并且不论你怎么变,你的测试仍可以通过。

耶!

所以如果指令不只是一组jQuery风格的函数,那么它们是什么呢?指令其实就是html的扩展。如果html不能完成你希望它做的一些事情,你就写一个指令来做,并且当它是html的一部分来使用。

换句话说, 如果Angular.js一下子无法完成手头的工作,想想看你的团队是否能用ngClick、ngClass等来搞定它。

以上内容主要是关于会jQuery,该如何用AngularJS编程思想,希望对大家有帮助。

相关推荐:

AngularJs增删改查的方法

用AngularJS的实现自定义服务

AngularJs表单验证的方法

以上是如何用AngularJS程式設計思想的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn