Answers:
在jQuery中,您可以设计一个页面,然后将其动态化。这是因为jQuery是为增强而设计的,并且在此简单前提下得到了难以置信的增长。
但是在AngularJS中,您必须从头开始,牢记架构。您不必从“我拥有DOM的这个部分,而我想使其成为X”开始,而是必须从要完成的事情开始,然后开始设计应用程序,然后最后开始设计视图。
同样,不要以jQuery做X,Y和Z的想法开始,所以我只在模型和控制器的基础上添加AngularJS。当您刚入门时,这确实很诱人,这就是为什么我总是建议新的AngularJS开发人员根本不使用jQuery,至少直到他们习惯于“ Angular Way”为止。
我在这里和邮件列表上已经看到许多开发人员使用jQuery插件(包含150或200行代码)创建了这些精心设计的解决方案,然后将它们粘贴到AngularJS中,并使用了一系列$apply
令人困惑和费解的回调和;但是他们最终使它起作用了!问题在于,在大多数情况下,可以在AngularJS中用少量代码重写jQuery插件,突然之间所有事情都变得容易理解和直接了。
底线是:解决时,首先“在AngularJS中思考”;如果您想不出解决方案,请询问社区;如果毕竟,有没有简单的解决方案,然后随意达到了jQuery。但是不要让jQuery成为拐杖,否则您将永远无法掌握AngularJS。
首先知道单页应用程序是application。它们不是网页。因此,除了像客户端开发人员那样思考之外,我们还需要像服务器端开发人员那样思考。我们必须考虑如何将应用程序划分为各个可扩展的可测试组件。
那你该怎么做呢?您如何“在AngularJS中思考”?这里有一些一般性的原则,与jQuery相反。
在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一半,并且没有好处。这里的问题是开发人员试图在AngularJS的上下文中“执行jQuery”。那永远行不通。该视图是官方记录。在指令之外(请参见下文),您永远不会更改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节点。而且,如果我们要删除日志条目,则也必须针对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>
现在,我们使用了Bootstrap警报框,而不是使用无序列表。而且,我们无需更改控制器代码!但更重要的是,无论在何处或如何更新日志,视图也会改变。自动地。整齐!
尽管这里没有显示,但数据绑定是双向的。因此,这些日志信息,也可以在视图编辑只是这样做:<input ng-model="entry.msg" />
。有很多的欣喜。
在jQuery中,DOM有点像模型。但是在AngularJS中,我们有一个单独的模型层,我们可以用它想要的任何方式进行管理,完全独立于视图。这有助于实现上述数据绑定,保持关注点分离,并引入更大的可测试性。其他答案都提到了这一点,所以我就把它留在那儿。
以上所有内容都与这个总体主题相关:将您的关注点分开。您的观点充当了将要发生的事情的正式记录(大部分情况下);您的模型代表您的数据;您有一个服务层来执行可重用的任务;您进行DOM操作并使用指令扩展视图;然后将它们与控制器粘合在一起。其他答案中也提到了这一点,我唯一要添加的内容就是可测试性,我将在下面的另一部分中进行讨论。
帮助我们分离关注点的是依赖注入(DI)。如果您来自服务器端语言(从Java到PHP),您可能已经熟悉此概念,但是如果您是来自jQuery的客户端人员,那么这个概念似乎从愚蠢到多余到时髦都不是。 。但事实并非如此。:-)
从广泛的角度来看,DI意味着您可以非常自由地声明组件,然后可以从任何其他组件中声明它们的实例,然后就可以授予它。您不必了解加载顺序,文件位置或类似内容。该功能可能不会立即可见,但我仅提供一个(常见)示例:测试。
假设在我们的应用程序中,我们需要一个服务,该服务通过REST API以及根据应用程序状态的本地存储来实现服务器端存储。在我们的控制器上运行测试时,我们不需要与服务器通信- 毕竟,我们正在测试控制器。我们只需添加一个与原始组件同名的模拟服务,然后注入器将确保我们的控制器自动获得伪造的服务-我们的控制器不需要也不知道有什么区别。
说到测试...
这确实是第3部分有关体系结构的一部分,但它非常重要,因此我将其作为自己的顶层部分。
在您已经看到,使用或编写的所有jQuery插件中,有多少具有相应的测试套件?并不是很多,因为jQuery不太适合这种情况。但是AngularJS是。
在jQuery中,测试的唯一方法通常是使用示例/演示页面独立创建组件,我们的测试可以针对该示例/演示页面执行DOM操作。因此,我们必须分别开发一个组件,然后将其集成到我们的应用程序中。多么不方便!很多时候,当使用jQuery开发时,我们选择迭代而不是测试驱动的开发。谁能责怪我们?
但是因为我们有关注点分离,所以我们可以在AngularJS中迭代进行测试驱动的开发!例如,假设我们要一个超级简单的指令在菜单中指示当前路线。我们可以在应用程序视图中声明我们想要的:
<a href="/hello" when-active>Hello</a>
好的,现在我们可以为不存在的when-active
指令编写测试:
it( 'should add "active" when the route changes', inject(function() {
var elm = $compile( '<a href="https://stackoverflow.com/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' );
}
});
}
};
});
现在,我们的测试通过了,并且菜单按要求执行。我们的开发既是迭代的又是测试驱动的。邪恶的酷。
您会经常听到“仅在指令中进行DOM操作”。这是必须的。谨慎对待它!
但是让我们深入一点...
有些指令只是修饰视图中已经存在的内容(认为ngClass
),因此有时会立即进行DOM操作,然后基本完成。但是,如果一个指令就像一个“小部件”并具有一个模板,则它也应该尊重关注点的分离。也就是说,模板在链接和控制器功能中也应在很大程度上与其实现无关。
AngularJS附带了一整套工具,使这一过程变得非常容易。与ngClass
我们可以动态更新的类; ngModel
允许双向数据绑定;ngShow
并以ngHide
编程方式显示或隐藏元素;还有更多-包括我们自己编写的内容。换句话说,我们可以在没有 DOM操作的情况下进行各种出色的工作。DOM操作越少,指令的测试就越容易,指令的样式就越容易,将来更改就越容易,它们的重用性和可分发性就越高。
我看到很多使用指令作为投掷jQuery的地方的AngularJS新手。换句话说,他们认为“由于我无法在控制器中进行DOM操作,因此我会将代码放入指令中”。虽然这肯定好得多,但通常仍然是错误的。
想想我们在第3节中编写的记录器。即使将其放入指令中,我们仍然希望以“ Angular Way”方式进行操作。它仍然不需要任何DOM操作!很多时候需要进行DOM操作,但这比您想像的要稀少得多!在对应用程序中的任何位置进行DOM操作之前,请问自己是否确实需要这样做。可能有更好的方法。
这是一个简单的示例,显示了我最常看到的模式。我们想要一个可切换的按钮。(请注意:此示例有些虚构,有些冗长,表示以完全相同的方式解决的更复杂的案例。)
.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);
});
}
};
});
这有一些问题:
angular.element
并且当我们的组件放入没有jQuery的项目时,它仍然可以工作。angular.element
)将始终使用jQuery,如果它是装的!因此我们不必使用$
-我们可以使用angular.element
。$
- element
传递给该link
函数的jqLite元素已经是 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;
};
}
};
});
同样,模板内容在模板中,因此您(或您的用户)可以轻松地将其替换为符合任何必需样式的样式,而无需触动逻辑。可重用性-繁荣!
而且还有所有其他好处,例如测试-很简单!无论模板中包含什么内容,该指令的内部API都不会被触及,因此重构很容易。您可以根据需要随意更改模板,而无需触摸指令。而且,无论您进行什么更改,您的测试仍然可以通过。
w00t!
因此,如果指令不仅仅是类似jQuery的函数的集合,它们是什么?指令实际上是HTML的扩展。如果HTML不能做您需要做的事情,您可以编写一条指令来为您做,然后像使用HTML一样使用它。
换句话说,如果AngularJS没做什么开箱,认为球队如何完成它适合对符合ngClick
,ngClass
等。
甚至不使用jQuery。甚至不包含它。它会让你退缩。并且当您遇到问题时,您认为自己已经知道如何使用jQuery解决问题,因此在$
尝试之前,请尝试考虑如何在AngularJS范围内解决该问题。如果您不知道,请询问!20的19倍中,最好的方法不需要jQuery,并尝试使用jQuery解决它会为您带来更多工作。
在jQuery中,选择器用于查找DOM元素,然后将事件处理程序绑定/注册到它们。当事件触发时,该(命令)代码将执行以更新/更改DOM。
在AngularJS中,您要考虑视图而不是DOM元素。视图是包含AngularJS 指令的(声明性)HTML 。指令为我们在后台设置了事件处理程序,并为我们提供了动态数据绑定。选择器很少使用,因此对ID(和某些类型的类)的需求大大减少了。视图与模型绑定(通过作用域)。视图是模型的投影。事件会更改模型(即数据,范围属性),并且投影这些模型的视图会“自动”更新。
在AngularJS中,请考虑模型,而不要考虑保存数据的jQuery选择的DOM元素。将视图视为这些模型的投影,而不是注册回调以操纵用户看到的内容。
jQuery使用了不引人注目的JavaScript-行为(JavaScript)与结构(HTML)是分开的。
AngularJS使用控制器和指令(每个控制器和指令可以具有自己的控制器,和/或编译和链接功能)从视图/结构(HTML)中删除行为。Angular还提供服务和过滤器,以帮助分离/组织您的应用程序。
另请参阅https://stackoverflow.com/a/14346528/215945
设计AngularJS应用程序的一种方法:
您可以在不了解JavaScript原型继承如何工作的情况下使用jQuery做很多事情。在开发AngularJS应用程序时,如果您对JavaScript继承有很好的了解,将避免一些常见的陷阱。推荐阅读:AngularJS中范围原型/原型继承的细微差别是什么?
on
并且when
是高阶函数,对jQuery集合对象的成员进行操作。
on
?势在必行。
AngularJS和jQuery采用非常不同的意识形态。如果您来自jQuery,则可能会发现其中一些令人惊讶的差异。有角可能会让你生气。
这是正常现象,您应该努力进行。Angular是值得的。
jQuery为您提供了一个工具包,用于选择DOM的任意位并对其进行临时更改。您可以一步一步地完成几乎所有您想做的事情。
AngularJS却给了你一个编译器。
这意味着AngularJS从头到尾读取您的整个DOM,并将其视为代码,从字面上看是对编译器的指令。在遍历DOM时,它会寻找特定的指令(编译器指令),这些指令告诉AngularJS编译器如何运行以及如何执行。指令是充满JavaScript的小对象,可以与属性,标签,类甚至注释进行匹配。
当Angular编译器确定DOM的一部分与特定指令匹配时,它将调用指令函数,并向其传递DOM元素,任何属性,当前的$ scope(这是一个局部变量存储区)以及一些其他有用的位。这些属性可能包含可由指令解释的表达式,这些表达式告诉指令如何渲染以及何时应重新绘制自身。
然后,指令又可以引入其他Angular组件,例如控制器,服务等。编译器的底部是一个完整的Web应用程序,已连接好并可以使用。
这意味着Angular是模板驱动的。您的模板将驱动JavaScript,而不是相反。这是角色的根本颠倒,这与过去十年左右我们一直在编写的不引人注目的JavaScript完全相反。这可能需要一些时间来适应。
如果这听起来像是过于规范和限制的话,那就没有比事实更遥远了。由于AngularJS将HTML视为代码,因此您可以在Web应用程序中获得HTML级别的粒度。一切皆有可能,一旦您实现了一些概念上的飞跃,大多数事情都将变得异常容易。
让我们开始讲究细节。
Angular和jQuery做不同的事情。AngularJS为您提供了一套用于生成Web应用程序的工具。jQuery主要为您提供了用于修改DOM的工具。如果页面上存在jQuery,AngularJS将自动使用它。如果不是这样,AngularJS将附带jQuery Lite,它是jQuery的精简版,但仍可完美使用。
Misko喜欢jQuery,并不反对使用它。但是,随着前进,您会发现可以使用范围,模板和指令的组合来完成几乎所有的工作,并且您应该尽可能使用此工作流,因为您的代码将更离散,更可配置且更多有角度的。
如果您确实使用jQuery,则不应将其散布在各处。在AngularJS中进行DOM操作的正确位置是在指令中。稍后再详细介绍。
jQuery通常会毫不客气地应用。您的JavaScript代码链接在页眉(或页脚)中,这是唯一提到的地方。我们使用选择器挑选页面的一部分,并编写插件来修改这些部分。
JavaScript受控制。HTML具有完全独立的存在。即使没有JavaScript,您的HTML仍保持语义。Onclick属性是非常不好的做法。
关于AngularJS的第一件事就是自定义属性无处不在。您的HTML会有ng属性,实际上是类固醇的onClick属性。这些是指令(编译器指令),并且是模板与模型挂钩的主要方式之一。
当您第一次看到此内容时,您可能会倾向于将AngularJS改写为老式的侵入式JavaScript(就像我刚开始那样)。实际上,AngularJS并不遵循这些规则。在AngularJS中,您的HTML5是模板。它由AngularJS编译以生成您的网页。
这是第一个大差异。对于jQuery,您的网页是要操作的DOM。对于AngularJS,您的HTML是要编译的代码。AngularJS读取整个网页,并使用其内置的编译器将其按字面意义编译为新网页。
您的模板应该是声明性的;只需阅读即可清楚了解其含义。我们使用具有有意义名称的自定义属性。我们用有意义的名称组成新的HTML元素。仅有很少的HTML知识并且没有编码技能的设计师可以阅读您的AngularJS模板并了解它的作用。他或她可以进行修改。这是角度的方式。
在启动AngularJS并运行教程时,我问自己的第一个问题是“我的代码在哪里?” 。我没有编写JavaScript,但是我有所有这些行为。答案是显而易见的。由于AngularJS会编译DOM,因此AngularJS会将您的HTML视为代码。在许多简单情况下,只需编写一个模板并让AngularJS为您编译成应用程序通常就足够了。
您的模板将驱动您的应用程序。它被视为DSL。您编写了AngularJS组件,AngularJS将根据模板的结构将它们拉入并在适当的时间使其可用。这与标准MVC模式非常不同,在标准MVC模式中,模板仅用于输出。
例如,它比Ruby on Rails更类似于XSLT。
这是一种彻底的控制反转,需要一定的习惯。
停止尝试从JavaScript驱动应用程序。让模板驱动应用程序,让AngularJS负责将组件连接在一起。这也是Angular方式。
使用jQuery,您的HTML页面应包含有意义的语义内容。如果关闭了JavaScript(由用户或搜索引擎关闭),您的内容仍然可以访问。
因为AngularJS将您的HTML页面视为模板。模板不应该是语义的,因为您的内容通常存储在模型中,而最终存储在您的API中。AngularJS使用模型编译您的DOM,以生成一个语义网页。
您的HTML源不再是语义的,而是您的API和已编译的DOM是语义的。
在AngularJS中,含义存在于模型中,HTML只是一个模板,仅用于显示。
在这一点上,您可能会遇到有关SEO和可访问性的各种问题,这是正确的。这里有未解决的问题。现在,大多数屏幕阅读器都会解析JavaScript。搜索引擎还可以索引AJAX内容。不过,您将需要确保使用的是pushstate URL,并且您拥有一个不错的站点地图。请参阅此处以获取有关该问题的讨论:https : //stackoverflow.com/a/23245379/687677
关注分离(SOC)是Web开发多年以来发展起来的一种模式,其原因包括SEO,可访问性和浏览器不兼容等多种原因。看起来像这样:
同样,AngularJS并不遵守他们的规则。很快,AngularJS放弃了十年的智慧,而是实现了一种MVC模式,其中模板不再是语义,甚至不再是语义。
看起来像这样:
MVC和SOC不在相同规模的相对两端,它们在完全不同的轴上。在AngularJS上下文中,SOC没有意义。您必须忘记它并继续前进。
如果像我一样,经历了浏览器大战,您可能会发现这个想法令人反感。克服它,这是值得的,我保证。
插件扩展了jQuery。AngularJS指令扩展了浏览器的功能。
在jQuery中,我们通过向jQuery.prototype添加函数来定义插件。然后,通过选择元素并在结果上调用插件,将它们挂接到DOM中。这个想法是为了扩展jQuery的功能。
例如,如果要在页面上使用轮播,则可以定义无序的图形列表,也许将其包装在nav元素中。然后,您可以编写一些jQuery以选择页面上的列表,然后将其重新设置为具有超时功能的图库,以进行滑动动画处理。
在AngularJS中,我们定义了指令。指令是一个返回JSON对象的函数。该对象告诉AngularJS寻找什么DOM元素,以及对其进行哪些更改。使用您发明的属性或元素将指令连接到模板。这个想法是用新的属性和元素扩展HTML的功能。
AngularJS的方法是扩展原生HTML的功能。您应该编写类似于HTML的HTML,并使用自定义属性和元素进行扩展。
如果您想要旋转木马,只需使用一个<carousel />
元素,然后定义一个指令以拉入模板,并使该吸盘工作。
jQuery的趋势是编写很棒的大型插件,例如lightbox,然后我们通过传入大量值和选项进行配置。
这是AngularJS中的错误。
以下拉列表为例。当编写一个下拉插件时,您可能会想在单击处理程序中编写代码,或者是一个添加人字形(向上或向下)的函数,或者更改展开元素的类,显示隐藏菜单,所有有用的东西。
直到您想做一点零钱。
假设您有一个要悬停展开的菜单。好吧,现在我们有一个问题。我们的插件已连接到我们的点击处理程序中,我们需要添加一个配置选项以使其在这种特定情况下表现不同。
在AngularJS中,我们编写了较小的指令。我们的下拉指令太小了。它可能会保持折叠状态,并提供fold(),unfold()或toggle()的方法。这些方法将简单地更新$ scope.menu.visible这是一个持有状态的布尔值。
现在,在我们的模板中,我们可以将其连接起来:
<a ng-click="toggle()">Menu</a>
<ul ng-show="menu.visible">
...
</ul>
是否需要更新鼠标悬停?
<a ng-mouseenter="unfold()" ng-mouseleave="fold()">Menu</a>
<ul ng-show="menu.visible">
...
</ul>
模板驱动应用程序,因此我们获得了HTML级别的粒度。如果我们要逐个案例地进行例外处理,则模板可以使此操作变得容易。
jQuery插件是在闭包中创建的。在此关闭内保持隐私。取决于您在该闭包内维护范围链。您实际上只能访问jQuery传递给插件的DOM节点集,以及在闭包中定义的任何局部变量以及您定义的任何全局变量。这意味着插件是完全独立的。这是一件好事,但在创建整个应用程序时可能会受到限制。试图在动态页面的各个部分之间传递数据变得很繁琐。
AngularJS具有$ scope对象。这些是由AngularJS创建和维护的特殊对象,您可以在其中存储模型。某些指令将产生一个新的$ scope,默认情况下,该$ scope使用JavaScript原型继承从其包装的$ scope继承。$ scope对象可在控制器和视图中访问。
这是聪明的部分。因为$ scope继承的结构大致遵循DOM的结构,所以元素可以无缝访问它们自己的作用域以及任何包含的作用域,一直到全局$ scope(与全局作用域不同)。
这样可以更轻松地传递数据并以适当的级别存储数据。如果展开下拉列表,则仅下拉列表$ scope需要知道它。如果用户更新了他们的首选项,则可能要更新全局$ scope,并且任何监听用户首选项的嵌套作用域都会自动得到警报。
这听起来可能很复杂,实际上,一旦您放松一下,就好像在飞翔。您不需要创建$ scope对象,AngularJS会根据您的模板层次结构正确正确地实例化并配置它。然后,AngularJS使用依赖注入的魔力将其提供给您的组件(稍后将对此进行更多介绍)。
在jQuery中,您可以手动更改所有DOM。您可以通过编程方式构造新的DOM元素。如果您有JSON数组并将其放入DOM,则必须编写一个函数来生成HTML并将其插入。
在AngularJS中,您也可以这样做,但建议您使用数据绑定。更改模型,由于DOM是通过模板绑定到模型的,因此DOM将自动更新,无需干预。
由于数据绑定是使用属性或大括号语法从模板完成的,因此非常容易做到。与之相关的认知开销很小,因此您会发现自己一直在这样做。
<input ng-model="user.name" />
将输入元素绑定到$scope.user.name
。更新输入将更新您当前作用域中的值,反之亦然。
同样地:
<p>
{{user.name}}
</p>
将在一个段落中输出用户名。这是实时绑定,因此如果$scope.user.name
值被更新,模板也将更新。
在jQuery中,进行Ajax调用非常简单,但是您仍然需要三思而行。需要考虑的额外复杂性和大量的脚本需要维护。
在AngularJS中,Ajax是您的默认入门解决方案,并且它一直在发生,几乎没有引起您的注意。您可以将模板包含在ng-include中。您可以使用最简单的自定义指令来应用模板。您可以将Ajax调用包装在服务中,并创建自己的GitHub服务或Flickr服务,您可以轻松地访问它们。
在jQuery中,如果我们想完成一个小的非dom相关的任务,例如从一个API中提取一个提要,我们可以在闭包中编写一个小函数来做到这一点。那是一个有效的解决方案,但是如果我们想经常访问该提要怎么办?如果我们想在另一个应用程序中重用该代码怎么办?
AngularJS给了我们服务对象。
服务是包含功能和数据的简单对象。它们始终是单例,这意味着不能超过一个。假设我们要访问Stack Overflow API,我们可以编写一个StackOverflowService
定义用于执行此操作的方法的。
假设我们有一个购物车。我们可以定义一个ShoppingCartService,它维护我们的购物车并包含添加和删除项目的方法。因为该服务是单例服务,并且由所有其他组件共享,所以任何需要写的对象都可以写入购物车并从中提取数据。总是同一个购物车。
服务对象是独立的AngularJS组件,我们可以根据需要使用和重用它们。它们是包含功能和数据的简单JSON对象。它们始终是单例,因此,如果将数据存储在某个位置的某个服务上,则可以通过请求相同的服务将数据导出到其他位置。
AngularJS为您管理依赖项。如果您想要一个对象,只需引用它,AngularJS就会为您提供。
除非您开始使用它,否则很难解释这是多么宝贵的时间。jQuery中没有像AngularJS DI那样的东西。
DI意味着您无需定义应用程序并将其连接在一起,而是可以定义一个组件库,每个组件由一个字符串标识。
假设我有一个名为“ FlickrService”的组件,该组件定义了用于从Flickr提取JSON提要的方法。现在,如果我想编写一个可以访问Flickr的控制器,则在声明该控制器时,只需按名称引用“ FlickrService”即可。AngularJS将负责实例化该组件并将其提供给我的控制器。
例如,在这里定义服务:
myApp.service('FlickrService', function() {
return {
getFeed: function() { // do something here }
}
});
现在,当我想使用该服务时,只需按如下名称命名:
myApp.controller('myController', ['FlickrService', function(FlickrService) {
FlickrService.getFeed()
}]);
AngularJS将认识到需要一个FlickrService对象来实例化控制器,并将为我们提供一个对象。
这使接线非常容易,并且几乎消除了任何可能出现幼化的趋势。我们有一个简单的组件列表,AngularJS在需要时将它们逐一交给我们。
jQuery很少说明应如何组织代码。AngularJS有意见。
AngularJS为您提供了可以在其中放置代码的模块。例如,如果您正在编写与Flickr对话的脚本,则可能需要创建一个Flickr模块来包装所有与Flickr相关的功能。模块可以包含其他模块(DI)。您的主应用程序通常是一个模块,并且应包括您的应用程序将依赖的所有其他模块。
您将获得简单的代码重用,如果您要编写基于Flickr的另一个应用程序,则可以仅包含Flickr模块和voila,您可以在新应用程序中访问所有与Flickr相关的功能。
模块包含AngularJS组件。当我们包含一个模块时,该模块中的所有组件都可以作为由其唯一字符串标识的简单列表提供给我们。然后,我们可以使用AngularJS的依赖项注入机制将这些组件相互注入。
AngularJS和jQuery不是敌人。可以在AngularJS中很好地使用jQuery。如果您很好地使用了AngularJS(模板,数据绑定,$ scope,指令等),您会发现所需的jQuery比您可能需要的要少得多。
要认识的主要是模板驱动您的应用程序。停止尝试编写可做所有事情的大插件。取而代之的是编写只做一件事的小指令,然后编写一个简单的模板将它们连接在一起。
少考虑不干扰JavaScript的内容,而应考虑HTML扩展。
我对AngularJS感到非常兴奋,为此写了一本简短的书,非常欢迎您在线阅读http://nicholasjohnson.com/angular-book/。希望对您有所帮助。
您能否描述必要的范式转换?
命令式与声明式
使用jQuery,您可以逐步告诉DOM需要做什么。使用AngularJS,您可以描述所需的结果,而不是所需的结果。更多关于此这里。另外,请查看Mark Rajcok的答案。
我如何以不同的方式设计和设计客户端Web应用程序?
AngularJS是使用MVC模式的完整客户端框架(请查看其图形表示)。它极大地侧重于关注点分离。
最大的区别是什么?我应该停止做什么/使用;我应该开始做什么/使用呢?
jQuery是一个库
AngularJS是一个漂亮的客户端框架,可测试性强,它结合了许多很酷的东西,例如MVC,依赖项注入,数据绑定等等。
它着重于关注点和测试的分离(单元测试和端到端测试),这有助于测试驱动的开发。
最好的开始方法是阅读他们很棒的教程。您可以在几个小时内完成所有步骤;但是,如果您想掌握幕后的概念,则其中包含许多参考资料供进一步阅读。
是否有服务器端注意事项/限制?
您可以在已经使用纯jQuery的现有应用程序上使用它。但是,如果您想充分利用AngularJS功能,则可以考虑使用RESTful方法对服务器端进行编码。
这样做将使您能够利用它们的资源工厂,这将创建服务器端RESTful API的抽象,并使服务器端调用(获取,保存,删除等)变得异常简单。
为了描述“范式转变”,我认为简短的回答就足够了。
在jQuery中,通常使用选择器查找元素,然后将它们连接起来:
$('#id .class').click(doStuff);
在AngularJS中,您使用指令直接标记元素,以将它们连接起来:
<a ng-click="doStuff()">
AngularJS不需要(也不希望)使用选择器来查找元素-AngularJS的jqLite与成熟的jQuery之间的主要区别是jqLite不支持选择器。
因此,当人们说“根本不包括jQuery”时,主要是因为他们不希望您使用选择器。他们希望您学习使用指令。直接,不选!
jQuery制作了很长的JavaScript命令,例如 getElementByHerpDerp
更短和跨浏览器。
AngularJS允许您创建自己的HTML标记/属性,这些标记/属性可以与动态Web应用程序一起很好地工作(因为HTML是为静态页面设计的)。
说“我有jQuery背景,在AngularJS中如何看待?” 就像说“我有HTML背景,我如何看待JavaScript?” 您所提问题的事实表明您很可能不了解这两种资源的基本目的。这就是为什么我选择通过简单地指出根本差异而不是在列表中遍历“ AngularJS使用指令,而jQuery使用CSS选择器来创建执行此操作的jQuery对象……”来回答这个问题的原因。 。这个问题不需要冗长的答案。
jQuery是一种使浏览器中的JavaScript编程更容易的方法。更短的跨浏览器命令等
AngularJS扩展了HTML,因此您不必为了编写<div>
应用程序而花很多精力。它使HTML实际上可用于应用程序,而不是为静态的教育性网页设计的。它使用JavaScript以一种about回的方式来完成此任务,但从根本上讲,它是HTML的扩展,而不是JavaScript。
$(".myclass")
在jQuery中非常常见,并且在jQuery中比PO-Javascript要容易得多。
jQuery:您对“查询DOM ”进行了很多思考对DOM元素的 ”进行并做了一些事情。
AngularJS:模型就是事实,您总是从那个角度思考。
例如,当您从服务器获取要以某种格式显示在DOM中的数据时,在jQuery中,您需要将其设置为'1。在DOM中要放置此数据的位置找到“ 2”。通过创建一个新节点或仅设置其innerHTML进行 “ UPDATE / APPEND”操作。然后,当您想更新此视图时,请输入'3。查找位置和“ 4。更新”。AngularJS中没有在从服务器获取和格式化数据的同一上下文中完成所有查找和更新的循环。
有了AngularJS,您就有了模型(您已经习惯了JavaScript对象),并且模型的值告诉您有关模型(显然)和视图的信息,并且对模型的操作会自动传播到视图,因此您无需不必考虑。您将发现自己在AngularJS中不再在DOM中找到东西。
要以另一种方式,在jQuery中,你需要考虑CSS选择器,那就是,哪里是div
或td
具有类或属性,等等,让我能得到他们的HTML或颜色或价值,但在AngularJS,您会发现自己是这样想的:我要处理的模型是什么,我将模型的值设置为true。您不必担心反映此值的视图是复选框还是驻留在td
元素中(详细信息,您通常需要在jQuery中进行思考)。
通过AngularJS中的DOM操作,您发现自己添加了指令和过滤器,可以将它们视为有效的HTML扩展。
您将在AngularJS中体验到另一件事:在jQuery中,您经常调用jQuery函数;在AngularJS中,AngularJS将调用您的函数,因此AngularJS将“告诉您如何做事”,但是好处是值得的,因此学习AngularJS通常意味着学习AngularJS想要什么或AngularJS要求您呈现函数的方式,它将相应地调用它。这是使AngularJS成为框架而不是库的原因之一。
jQuery是一个DOM操作库。
AngularJS是MV *框架。
实际上,AngularJS是少数JavaScript MV *框架之一(许多JavaScript MVC工具仍属于类别库)。
作为一个框架,它托管您的代码,并拥有有关调用内容和时间的决策的所有权!
AngularJS本身包含一个jQuery-lite版本。因此,对于某些基本的DOM选择/操作,您实际上不必包括jQuery库(它节省了很多字节以在网络上运行)。
AngularJS具有用于DOM操作和设计可重用UI组件的“指令”的概念,因此,当您需要进行与DOM操作相关的工作时,应该使用它(指令仅是在使用AngularJS时应编写jQuery代码的地方)。
AngularJS涉及一些学习曲线(不仅仅是jQuery :-)。
->对于所有来自jQuery背景的开发人员,我的第一条建议是“在跳入AngularJS之类的丰富框架之前,将JavaScript作为一流的语言学习!” 我很难学到上述事实。
祝好运。
他们是苹果和橘子。您不想比较它们。他们是两回事。AngularJs已经内置了jQuery lite,它允许您执行基本的DOM操作,甚至不包括完整的jQuery版本。
jQuery全部涉及DOM操作。它解决了所有跨浏览器的烦恼,否则您将不得不面对,但它不是一个框架,可让您将应用程序划分为AngularJS之类的组件。
关于AngularJs的好处是,它允许您在指令中分隔/隔离DOM操作。有内置指令可供您使用,例如ng-click。您可以创建自己的自定义指令,其中将包含所有视图逻辑或DOM操作,这样您就不会最终在应该处理业务逻辑的控制器或服务中混合DOM操作代码。
Angular将您的应用细分为-控制器-服务-视图-等
还有一件事,那就是指令。它是一个属性,可以附加到任何DOM元素,并且可以在其中使用jQuery,而不必担心jQuery与AngularJs组件发生冲突或弄乱其体系结构。
我从参加的聚会中听说,Angular的一位创始人表示,他们非常努力地将DOM操作分离出来,所以不要尝试将其重新加入。
收听播客JavaScript Jabber:第32集,其中介绍了AngularJS的原始创建者:Misko Hevery和Igor Minar。他们谈论了来自其他JavaScript背景(尤其是jQuery)的AngularJS的感受。
在播客中提出的观点之一,就您的问题而言,很多事情对我来说都很重要:
MISKO:[...]我们在Angular中很少想到的一件事是,我们如何提供大量的逃生舱口,以便您可以走出来并从根本上找出解决办法。因此,对我们来说,答案就是这个叫做“指令”的东西。有了指令,您实际上就变成了普通的小型jQuery JavaScript,您可以做任何您想做的事情。
IGOR:因此,可以将指令视为编译器的指令,当您在模板中遇到此特定元素或此CSS时会告诉它,并且您保留此类代码,并且该代码负责该元素以及该元素下的所有内容在DOM树中。
整个情节的笔录可从上面提供的链接中获得。
因此,直接回答您的问题:AngularJS是非常有思想的,并且是一个真正的MV *框架。但是,您仍然可以在指令内部使用jQuery完成所有您知道并喜欢的非常酷的工作。这与“我该如何执行jQuery中以前的工作?”无关紧要。与“我如何用以前在jQuery中做的所有事情补充AngularJS?”一样多。
这实际上是两种截然不同的心态。
我发现这个问题很有趣,因为我最先接触JavaScript编程的是Node.js和AngularJS。我从来没有学过jQuery,我想那是一件好事,因为我不必学习任何东西。实际上,我积极地避免了针对我的问题的jQuery解决方案,而是仅寻找“ AngularJS方式”来解决它们。因此,我想我对这个问题的回答本质上可以归结为“像从未学习过jQuery的人一样思考”,并避免了直接集成jQuery的任何诱惑(显然AngularJS在后台使用了它)。
AngularJS和jQuery:
除了JQLite功能以外,AngularJs和JQuery在每个级别上都完全不同,一旦您开始学习AngularJs的核心功能(我在下面解释了),您就会看到它。
AngularJs是一个客户端框架,可用来构建独立的客户端应用程序。JQuery是围绕DOM播放的客户端库。
AngularJs酷原则-如果要在UI上进行一些更改,请从模型数据更改角度考虑。更改数据,UI会重新呈现。除非并直到几乎没有要求,否则您不必每次都在DOM上玩耍,这也应该通过Angular Directives处理。
为了回答这个问题,我想与AngularJS分享我在第一个企业应用程序上的经验。这些是Angular提供的最令人敬畏的功能,我们可以在这些功能上开始改变jQuery的思维方式,并获得Angular像框架而不是库。
双向数据绑定是惊人的: 我拥有一个具有所有功能UPDATE,DELTE,INSERT的网格。我有一个使用ng-repeat绑定网格模型的数据对象。您只需要编写一行简单的JavaScript代码即可进行删除和插入,仅此而已。网格模型立即更改时,网格会自动更新。更新功能是实时的,没有代码。你感觉很棒!!!
可重用指令是超级的: 在一个地方编写指令,并在整个应用程序中使用它。我的天啊!!!我将这些指令用于分页,正则表达式,验证等。这真的很棒!
路由功能很强大: 取决于您的实现方式,但要用很少的代码行来路由请求以指定HTML和控制器(JavaScript)
控制器很棒: 控制器会照顾好自己的HTML,但是这种分离对于通用功能也很有效。如果要单击主HTML上的按钮来调用相同的函数,只需在每个控制器中写入相同的函数名称并编写单独的代码即可。
插件: 还有许多其他类似功能,例如在您的应用程序中显示覆盖图。您不需要为此编写代码,只需使用可作为wc-overlay使用的overlay插件,它将自动处理所有XMLHttpRequest(XHR)请求。
RESTful体系结构的理想选择: 完整的框架使AngularJS非常适合与RESTful体系结构一起使用。调用REST CRUD API非常容易,并且
服务:使用服务编写通用代码,而在控制器中编写更少的代码。服务可用于在控制器之间共享通用功能。
可扩展性:Angular已使用angular指令扩展了HTML指令。在html内编写表达式,并在运行时对其求值。创建您自己的指令和服务,并在其他项目中使用它们,而无需进行任何额外的工作。
作为JavaScript MV *的初学者,并且只专注于应用程序体系结构(而不是服务器/客户端问题),我当然会推荐以下资源(我还没有提及到我很惊讶):JavaScript设计模式,作者:Addy Osmani ,介绍不同的JavaScript设计模式。该答案中使用的术语取自上面的链接文档。我不会在已接受的答案中重复非常好的措词。相反,此答案可以链接到为AngularJS(和其他库)提供支持的理论背景。
像我一样,您会很快意识到AngularJS(或者Ember.js,Durandal以及其他MV *框架)是一个复杂的框架,它集合了许多不同的JavaScript设计模式。
我发现它也更容易,以测试(1)天然的JavaScript代码和(2)对于这些模式中的每一个更小的文库分别潜水成一个全球框架之前。这使我可以更好地了解框架解决了哪些关键问题(因为您亲自面对该问题)。
例如:
注意:此列表并不完整,也不是“最佳图书馆”。它们恰好是我使用的库。这些库还包含更多模式,其中提到的只是它们的主要重点或原始意图。如果您觉得此列表中缺少某些内容,请在评论中提及它,我们将很高兴添加它。
实际上,如果您使用的是AngularJS,则不再需要jQuery。AngularJS本身具有绑定和指令,对于您可以使用jQuery进行的大多数操作而言,这是一个很好的“替代品”。
我通常使用AngularJS和Cordova开发移动应用程序。我唯一需要的jQuery是Selector。
通过谷歌搜索,我看到那里有一个独立的jQuery选择器模块。是嘶嘶声。
然后,我决定制作一个很小的代码段,以帮助我使用jQuery Selector(使用Sizzle)使用AngularJS快速启动网站。
我在这里分享了我的代码:https : //github.com/huytd/Sizzular