javascript - element用法




如果我有jQuery背景,“在AngularJS中思考”? (10)

假设我熟悉在jQuery开发客户端应用程序,但现在我想开始使用AngularJS 。 你能描述一下必要的范式转变吗? 以下是一些可能有助于您确定答案的问题:

  • 如何以不同方式构建和设计客户端Web应用程序? 最大的区别是什么?
  • 我应该停止做什么/使用什么; 我应该开始做什么/使用什么呢?
  • 有任何服务器端考虑因素/限制吗?

我不是在寻找jQueryAngularJS之间的详细比较。


你能描述一下必要的范式转变吗?

势在必行与陈述

使用jQuery,您可以一步一步地告诉DOM需要发生什么。使用AngularJS您可以描述您想要的结果,但不能描述如何执行此操作。更多关于here。另外,请查看Mark Rajcok的答案。

如何以不同方式构建和设计客户端Web应用程序?

AngularJS是一个使用MVC模式的完整客户端框架(查看其图形表示)。它非常注重关注点的分离。

最大的区别是什么? 我应该停止做什么/使用什么; 我应该开始做什么/使用呢?

jQuery是一个库

AngularJS是一个漂亮的客户端框架,高度可测试,它结合了许多很酷的东西,如MVC,依赖注入,数据绑定等等。

它侧重于关注点和测试(单元测试和端到端测试)的分离,这有助于测试驱动的开发。

最好的方法是通过他们的精彩教程。你可以在几个小时内完成这些步骤; 但是,如果你想掌握幕后的概念,它们包含了无数的参考资料以供进一步阅读。

有任何服务器端考虑因素/限制吗?

您可以在已经使用纯jQuery的现有应用程序上使用它。但是,如果您想充分利用AngularJS功能,可以考虑使用RESTful方法对服务器端进行编码。

这样做将允许您利用他们的资源工厂,它创建服务器端RESTful API的抽象,并使服务器端调用(获取,保存,删除等)非常容易。


1.不要设计页面,然后使用DOM操作进行更改

在jQuery中,您设计了一个页面,然后将其设置为动态。 这是因为jQuery是为增强而设计的,并且从这个简单的前提中获得了令人难以置信的增长。

但是在AngularJS中,您必须从头开始考虑您的架构。 而不是首先考虑“我有这块DOM,我想让它做X”,你必须从你想要完成的事情开始,然后去设计你的应用程序,然后最后去设计你的视图。

2.不要使用AngularJS扩充jQuery

同样,不要从jQuery做X,Y和Z的想法开始,所以我只是在模型和控制器的基础上添加AngularJS。 当你刚刚开始时,这真的很诱人,这就是为什么我总是建议新的AngularJS开发人员根本不使用jQuery,至少在他们习惯于“Angular Way”做事之前。

我在这里和邮件列表上看到很多开发人员使用150或200行代码的jQuery插件创建这些精心设计的解决方案,然后他们将这些代码粘合到AngularJS中,其中包含一系列令人困惑和错综复杂的回调和$apply ; 但他们最终让它发挥作用! 问题在于,在大多数情况下,jQuery插件可以在AngularJS中以一小部分代码重写,突然间一切都变得易于理解和直接。

最重要的是:在解决问题时,首先要“在AngularJS中思考”; 如果你想不出解决方案,请问社区; 如果完全没有简单的解决方案, 那么随时可以找到jQuery。 但是不要让jQuery成为拐杖或者你永远不会掌握AngularJS。

3.始终从架构的角度思考

首先要知道单页应用程序应用程序 。 他们不是网页。 因此,我们需要像服务器端开发人员一样思考,而不是像客户端开发人员那样思考。 我们必须考虑如何将我们的应用程序划分为单独的,可扩展的,可测试的组件。

那你怎么做的呢? 你如何“在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)。 如果你来自服务器端语言(从JavaPHP ),你可能已经熟悉了这个概念,但如果你是一个来自jQuery的客户端人,那么这个概念可能看起来从愚蠢到多余到时髦。 但事实并非如此。 :-)

从广义的角度来看,DI意味着您可以非常自由地声明组件,然后从任何其他组件声明组件,只需要询问它的实例,它就会被授予。 您无需了解加载顺序,文件位置或类似内容。 电源可能不会立即可见,但我只提供一个(常见)示例:测试。

让我们说在我们的应用程序中,我们需要一个通过REST API实现服务器端存储的服务,并且根据应用程序状态,还需要本地存储。 在我们的控制器上运行测试时,我们不希望与服务器通信 - 毕竟我们正在测试控制器 。 我们可以添加一个与原始组件同名的模拟服务,注入器将确保我们的控制器自动获取假的 - 我们的控制器不会,也不需要知道差异。

说到测试......

4.测试驱动的开发 - 永远

这实际上是关于体系结构的第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="/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' );
                }
            });
        }
    };
});

我们的测试现在通过我们的菜单按要求执行。 我们的开发既是迭代的, 也是测试驱动的。 妖兽爽。

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

您经常会听到“只在指令中执行DOM操作”。 这是必要的。 善意对待它!

但是让我们深入一点......

一些指令只是装饰视图中的内容(想想ngClass ),因此有时会直接进行DOM操作,然后基本完成。 但是如果指令就像一个“小部件”并且有一个模板,那么它应该尊重关注点的分离。 也就是说,模板应该在很大程度上独立于链接和控制器功能中的实现。

AngularJS附带了一整套工具,可以轻松实现这一目标。 使用ngClass我们可以动态更新类; ngModel允许双向数据绑定; ngShowngHide编程方式显示或隐藏元素; 还有更多 - 包括我们自己写的那些。 换句话说,我们可以在没有 DOM操作的情况下做各种各样的超棒。 DOM操作越少,测试指令就越容易,它们的样式就越容易,将来它们就越容易改变,它们的可重用性和可分发性就越高。

我看到许多开发人员对AngularJS很新,使用指令作为抛出一堆jQuery的地方。 换句话说,他们认为“因为我不能在控制器中进行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);
            });
        }
    };
});

这有一些问题:

  1. 首先,jQuery从来都不是必需的。 我们在这里做的一切都不需要jQuery!
  2. 其次,即使我们的页面上已经有jQuery,也没有理由在这里使用它; 我们可以简单地使用angular.element ,当我们放入没有jQuery的项目时,我们的组件仍然可以工作。
  3. 第三,即使假设此指令需要jQuery才能工作,jqLit​​e( angular.element )将始终使用jQuery(如果已加载)! 所以我们不需要使用$ - 我们可以使用angular.element
  4. 第四,与第三个密切相关的是,jqLit​​e元素不需要包装在$ - 传递给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;
            };
        }
    };
});

同样,模板内容在模板中,因此您(或您的用户)可以轻松地将其交换为满足任何必要样式的模板,并且不必触及逻辑 。 可重用性 - 热潮!

还有所有其他好处,比如测试 - 这很容易! 无论模板中有什么内容,指令的内部API都不会被触及,因此重构很容易。 您可以根据需要更改模板,而无需触及指令。 无论你改变什么,你的测试仍然通过。

w00t!

因此,如果指令不仅仅是类jQuery函数的集合,它们是什么? 指令实际上是HTML的扩展 。 如果HTML不需要它做某事,你可以编写一个指令来为你做,然后就像使用它一样使用它。

换句话说,如果AngularJS没有开箱即用,请考虑团队如何完成它以适应ngClickngClass等。

摘要

甚至不使用jQuery。 甚至不包括它。 它会阻止你。 当你遇到一个问题,你认为你已经知道如何在jQuery中解决,在你达到$ ,试着考虑如何在AngularJS的范围内做到这一点。 如果你不知道,请问! 20次中有19次,最好的方法是不需要jQuery并尝试使用jQuery解决它,为您提供更多的工作。


jQuery的

jQuery制作了一些可笑的长命令,比如getElementByHerpDerp简短和跨浏览器。

AngularJS

AngularJS允许您创建自己的HTML标记/属性,这些标记/属性可以很好地处理动态Web应用程序(因为HTML是为静态页面设计的)。

编辑:

说“我有一个jQuery背景我如何在AngularJS中思考?” 就像说“我有一个HTML背景我如何在JavaScript中思考?” 您提出问题的事实表明您很可能不理解这两种资源的基本目的。这就是为什么我选择通过简单地指出基本区别来回答问题,而不是通过列表说“AngularJS使用指令,而jQuery使用CSS选择器来创建一个jQuery对象来执行此操作等等......” 。这个问题不需要冗长的答案。

jQuery是一种使浏览器中的JavaScript编程更容易的方法。更短,跨浏览器的命令等

AngularJS扩展了HTML,因此您不必<div>为了创建应用程序而将所有地方放在一起。它使HTML实际上适用于应用程序而不是它的设计目标,即静态的教育网页。它使用JavaScript以迂回的方式实现这一点,但从根本上说它是HTML的扩展,而不是JavaScript。


势在必行→陈述性

在jQuery中, 选择器用于查找DOM元素,然后将事件处理程序绑定/注册到它们。 当事件触发时,执行(命令性)代码以更新/更改DOM。

在AngularJS中,您需要考虑视图而不是DOM元素。 视图是包含AngularJS 指令的 (声明性)HTML。 指令为我们幕后设置了事件处理程序,并为我们提供了动态数据绑定。 选择器很少使用,因此对ID(以及某些类型的类)的需求大大减少。 视图与模型相关 (通过范围)。 视图是模型的投影。 事件更改模型(即数据,范围属性)以及投影这些模型的视图会“自动”更新。

在AngularJS中,考虑模型,而不是jQuery选择的DOM元素来保存您的数据。 将视图视为这些模型的投影,而不是注册回调来操纵用户看到的内容。

关注点分离

jQuery使用不引人注目的JavaScript - 行为(JavaScript)与结构(HTML)分离。

AngularJS使用控制器和指令(每个控制器和指令可以有自己的控制器和/或编译和链接函数)来从视图/结构(HTML)中删除行为。 Angular还提供服务过滤器,以帮助分离/组织您的应用程序。

另请参见https://.com/a/14346528/215945

应用设计

设计AngularJS应用程序的一种方法:

  1. 想想你的模特。 为这些模型创建服务或您自己的JavaScript对象。
  2. 想想你想要如何展示你的模特 - 你的观点。 为每个视图创建HTML模板,使用必要的指令来获取动态数据绑定。
  3. 将控制器连接到每个视图(使用ng-view和routing,或ng-controller)。 让控制器只查找/获取视图完成其工作所需的任何模型数据。 使控制器尽可能薄。

原型继承

你可以在不知道JavaScript原型继承如何工作的情况下使用jQuery做很多事情。 在开发AngularJS应用程序时,如果您对JavaScript继承有很好的理解,就可以避免一些常见的陷阱。 推荐阅读: 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中,您通常使用选择器来查找元素,然后将它们连接起来:
$('#id .class').click(doStuff);

AngularJS中,您可以使用指令直接标记元素,以便将它们连接起来:
<a ng-click="doStuff()">

AngularJS并不需要(或希望)你找到使用选择元素- AngularJS的之间的主要区别jqLit​​e与全面的jQuery的jqLit​​e不支持选择

所以当人们说“根本不包含jQuery”时,主要是因为他们不希望你使用选择器; 他们希望你学习使用指令。直接,不选择!


jQuery:你对DOM元素的“查询DOM ”以及做某事有很多想法。

AngularJS:模型是事实,你总是从那个角度思考。

例如,当您从要在DOM中以某种格式显示的服务器获取数据时,在jQuery中,您需要'1。找到'你要在DOM中放置这些数据的位置,'2。通过创建新节点或仅设置其innerHTML更新/附加它。然后,当您想要更新此视图时,您将'3。找到'位置'和'4。UPDATE”。在AngularJS中,在从服务器获取和格式化数据的相同上下文中完成所有查找和更新循环。

使用AngularJS,您可以获得模型(已经习惯的JavaScript对象),模型的值会告诉您模型(显然)和视图,模型上的操作会自动传播到视图,所以你不要我必须考虑一下。你会发现自己在AngularJS中不再在DOM中找到东西。

要以另一种方式,在jQuery中,你需要考虑的CSS选择器,那就是,哪里是divtd具有类或属性,等等,让我能得到他们的HTML或颜色或价值,但在AngularJS,你会发现自己这样想:我在处理什么模型,我会将模型的值设置为true。您不必担心反映此值的视图是复选框还是驻留在td元素中(您在jQuery中经常需要考虑的细节)。

在AngularJS中使用DOM操作,您会发现自己添加了指令和过滤器,您可以将其视为有效的HTML扩展。

你将在AngularJS中体验到的另一件事:在jQuery中你调用jQuery函数很多,在AngularJS中,AngularJS会调用你的函数,所以AngularJS会“告诉你如何做事”,但是它的好处是值得的,所以学习AngularJS通常意味着学习AngularJS想要的东西或者AngularJS要求你展示你的功能的方式,它会相应地调用它。这是使AngularJS成为框架而不是库的因素之一。


他们是苹果和橘子。你不想比较它们。他们是两件不同的事。AngularJs已经内置了jQuery lite,它允许你执行基本的DOM操作,甚至不包括完整的jQuery版本。

jQuery是关于DOM操作的。它解决了所有跨浏览器的痛苦,否则你将不得不处理,但它不是一个允许你将你的应用程序划分为AngularJS等组件的框架。

AngularJs的一个好处是它允许你在指令中分离/隔离DOM操作。有内置指令可供您使用,例如ng-click。您可以创建自己的自定义指令,其中包含所有视图逻辑或DOM操作,因此您最终不会将DOM操作代码混合在应该处理业务逻辑的控制器或服务中。

Angular将您的应用分解为 - 控制器 - 服务 - 视图 - 等

还有一件事,就是指令。它是一个可以附加到任何DOM元素的属性,你可以在其中使用jQuery,而不必担心你的jQuery会与AngularJs组件发生冲突或者与它的架构混淆。

我从参加过的聚会中听到,Angular的一位创始人表示他们非常努力地将DOM操作分开,所以不要试图将它们包括在内。


实际上,如果您使用的是AngularJS,则不再需要jQuery。AngularJS本身具有绑定和指令,对于您可以使用jQuery执行的大多数事情来说,这是一个非常好的“替代”。

我通常使用AngularJS和Cordova开发移动应用程序。我需要的jQuery唯一的东西是Selector。

通过谷歌搜索,我看到有一个独立的jQuery选择器模块。这是嘶嘶声。

我决定制作一个小代码片段,帮助我使用AngularJS快速启动一个具有jQuery Selector功能的网站(使用Sizzle)。

我在这里分享了我的代码:https://github.com/huytd/Sizzularhttps://github.com/huytd/Sizzular


我发现这个问题很有意思,因为我第一次认真接触JavaScript编程的是Node.js和AngularJS。我从来没有学过jQuery,我想这是件好事,因为我不需要忘记任何事情。事实上,我主动避免jQuery解决方案来解决我的问题,而只是寻找一种“AngularJS方式”来解决它们。所以,我想我对这个问题的回答基本上归结为“想象一个从未学过jQuery的人”,并避免任何直接合并jQuery的诱惑(显然AngularJS在某种程度上在幕后使用它)。







angularjs