AngularJS最佳实践和技巧

Share

这个资源包含了由Toptal网络成员提供的AngularJS最佳实践和技巧的集合.

这个资源包含了由Toptal网络成员提供的AngularJS最佳实践和技巧的集合. As such, 本页将定期更新,以包含更多的信息和新兴的AngularJS技术. 这是一个社区驱动的项目, 所以我们也鼓励你们做出贡献, 我们期待着你们的反馈.

不像其他JavaScript框架, AngularJS要求开发者以“Angular”的方式做事, 这是一套规则和最佳实践,对正确构建AngularJS web应用程序至关重要. 在这里,我们将采用那些将使你成为更好的AngularJS开发人员的最佳实践.

有关AngularJS的更多信息,请查看total资源页面 common mistakes, AngularJS job description and AngularJS interview questions.

Tip Proposed by Srinu

Author Name: Srinu 作者邮箱:srinum666666@gmail.com

你的解释方式很好. You add some valuable points. 这里我将分享一些关于Angular的信息. Angular是一个用于开发前端应用程序的JavaScript框架. angular是一个平台,可以让你很容易地用web构建应用程序. Angular结合了声明式模板, dependency injection, end-to-end tooling, 以及解决发展挑战的综合最佳实践. Angular使开发人员能够构建web、移动或桌面应用. 如果你比较了其他框架,那么最好从AngularJS开始. 您还可以学习另一个框架. 通常,它们遵循相同的设计和实现模式. 是的,AngularJS有很好的作用域. 寻找最好的角训练加入Apec角训练在Ameerpet海得拉巴. 在海德拉巴的角训练

从Toptal获取最新的开发人员更新.

订阅意味着同意我们的 privacy policy

在指令中使用' bindToController '.

编写指令时,Angular的最佳实践之一是使用 controllerAs syntax. 这种语法在控制器中为我们提供了一个本地命名空间.

记住,这个变化是在Angular版本1中引入的.2. 在此之前,所有人都在使用mystic编写控制器 $scope 对象,结果是 $parent 问题和DOM周围的属性.

The controllerAs 语法使我们能够将控制器实例化为类对象. 在普通JavaScript中,这看起来像这样:

var aClass = function () {
  this.name = "My class";
};
var instance = new aClass();

Here, we can use the instance 变量访问方法和属性 aClass. In Angular, with controllerAs 控制器也有类似的语法.

介绍了基础知识之后,我们现在可以回到主题上来了. 写入控制器时使用 controllerAs 语法我们会遇到一些问题. 我们把组件写成类对象,但是我们继续注入 $scope 仅用于访问隔离的作用域属性:

函数控制器($scope, getnamefromsomeeservice) {
  this.foo = {};
  this.do = function () {
    getNameFromSomeService.get().then(function (response) {
      this.foo.bar = 'something';
      $scope.name = response; //reference to the isolated property
    }.bind(This));
  }
}

function directive () {
  return {
    restrict: 'E',
    scope: {
      name: '='
    },
    controller: 'controller',
    controllerAs: 'vm',
    templateUrl:“一些/模板/文件.html'
  }
}

angular.module('app')
.控制器(控制器,控制器)
.指令(myDirective,指令);

如你所见,我们的控制器需要注入 $scope only to get access to name property. 我们想摆脱这个对象,采用Angular的最佳实践.

bindToController to Rescue

The bindToController 属性允许我们将独立的属性绑定到控制器对象,而不是 $scope. Quote from the documentation:

当为组件使用隔离作用域时(见上文), and controllerAs is used, bindToController: true将允许组件将其属性绑定到控制器, rather than to scope. 当控制器实例化时, 隔离范围绑定的初始值已经可用.

考虑到这一点,我们可以这样重构控制器:

函数控制器(getNameFromSomeService) {
  this.foo = {};
  this.do = function () {
    getNameFromSomeService.get().then(function (response) {
      this.foo.bar = 'something';
      this.name = response; //reference to the isolated property but using `this`
    }.bind(This));
  }
}

function directive () {
  return {
    restrict: 'E',
    scope: {
      name: '='
    },
    bindToController: true
    controller: 'controller',
    controllerAs: 'vm',
    templateUrl:“一些/模板/文件.html'
  }
}

值得注意的是,这个新属性比文档中描述的功能更强大. 您可以使用object来定义属性,这将允许您从 scope definition to bindToController

{% highlight javascript %}
function directive () {
  return {
    restrict: 'E',
    scope: {},
    bindToController: {
      name: '='
    },
    controller: 'controller',
    controllerAs: 'vm',
    templateUrl:“一些/模板/文件.html'
  }
}

现在我们的控制器不需要注入 $scope (我们只需要事件或观察者).

在此重构之后,我们还需要更改模板. 原始模板可能看起来像这样:

我们需要将这个模板更改为以下模板:

Now the name property is accessed from the vm namespacing.

如何使“ng-click”有条件?

假设您有一个必须始终可见的元素,无论用户是否登录. 如果用户登录了,元素需要是可点击的. 示例伪代码看起来像这样:

Click me

Unfortunately, ng-if is not an option. 如果ng-if设置为false,则根本不会看到该元素. 你可以让它一直是可点击的, 然后在输入ng-click功能时检查用户是否登录, 但这不是最好的解决方案.

对于这个问题,Toptal的工程师们提出了两种解决方案.

一种解决方案是在函数调用之前使用布尔表达式,如下例所示:

Click me

该解决方案可以工作,但不容易阅读,因此不推荐使用. 对代码使用非标准技术和应用技巧可能会成为一个很大的代码维护问题. 即使是编写代码的开发人员也可能忘记他正在解决什么问题, 以及为什么要这样写. 如果有新的开发商接手怎么办?

另一种解决方案涉及编写更多的HTML代码,并添加两个具有不同行为的相同元素.

在这种情况下,示例伪代码看起来像这样:

Click me
You can’t click me

This should work well, 特别是当重复的元素很小的时候, 但在处理大量DOM元素时,不建议这样做. 消除这个缺点的一种方法是将元素放入单独的模板中, so, even if the code is duplicated, it becomes more readable.

Contributors

Richard Smuts

Freelance AngularJS Developer

South Africa

理查德是一个友好、健谈、外向、聪明的人,喜欢解决问题. 他仔细评估一项任务的要求, 抓住机会仔细思考,并有效地生产易于维护和完整的产品.

Show More

Kamil Burzynski

Freelance AngularJS Developer

Poland

Kamil是一位经验丰富的全栈web开发人员, 能够完成从概念阶段到建筑设计的复杂项目, implementation, and DevOps to maintenance. 他全程负责所有的技术细节,这样他的客户就不必这么做了!

Show More

如何部署AngularJS应用?

有不止一种方法可以给系统架构添加皮肤. Toptal的AngularJS专业工程师是如何做到的?

Toptal的一位开发人员最近描述了他成功实现的一个系统架构. 应用程序所需的每个服务, be it a load balancer, a database, or the app server, is run in its own Docker 图像被缩小了 Service-Oriented Architecture. This way, 对于每个生产推送,只有少数映像被重新部署, 让其他设备不受干扰地运行.

这种方法的优点是不需要担心服务器配置. With Docker, 您可以轻松地在笔记本电脑上创建生产环境, test it, play with it, 然后在生产服务器上启动相同的虚拟机映像,并且仍然100%确定它们将以相同的方式运行. 您还可以随时轻松地废弃整个服务器,并通过脚本重新构建它. 在这种情况下,软件将始终在原始环境中运行. For example, 有时需要配置服务器, 编辑一个系统配置文件,然后忘记它,你的软件工作良好. 但是当您尝试在另一台服务器上运行它时(该服务器没有您忘记的配置更改), 您的软件将无法运行,您将花费大量时间来解决这个“奇怪”的问题. With Docker, such things do not exist; servers are re-built with 100 percent repeatability.

使用Docker的另一个优点是,它允许您轻松地分离架构中各个部分的依赖关系. 例如,如果您的web服务器需要Ruby 2.x和应用程序的其他部分(如一些后台工作器)需要Ruby 1.通常情况下,很难让它在单个服务器上工作. With Docker, you bundle Ruby 2.Ruby 1 . x和应用服务器.X和另一张照片上的工人,他们愉快地生活在一起,一点也不干涉.

你是如何管理这么多图像的? 部署配置工具,如 Ansible do the trick nicely. 通过给你简单和全面的控制系统配置, version tracking, and deployments, 管理整个构建非常简单. 您可以编写用于远程设置Docker的可见代码片段, 将机器映像传输到服务器, 然后远程启动容器, 以及一些最小的管理配置,以便在出现问题时保持它们的活力. So basically, 你最终将整个应用程序同时部署到多个服务器上, 而无需手动对任何这些服务器执行SSH操作. 通过确保仔细执行Ansible脚本, and in the right order, 通过使用微服务架构执行滚动升级,相对容易实现零停机时间, 所有部件都是重复的,并且位于负载均衡器后面.

唯一的缺点是这种设置的复杂性,所以它不适合新手开发人员.

Contributors

Kamil Burzynski

Freelance AngularJS Developer

Poland

Kamil是一位经验丰富的全栈web开发人员, 能够完成从概念阶段到建筑设计的复杂项目, implementation, and DevOps to maintenance. 他全程负责所有的技术细节,这样他的客户就不必这么做了!

Show More

如何正确使用“controllerAs”语法?

Angular是一个非常强大的框架, 有时过于强大会导致一些开发人员犯一些架构错误. 双向数据绑定和指令的强大功能令人敬畏, 但是您需要考虑您在做什么,并尝试使用一些最佳实践来避免开发过程中的常见陷阱.

控制器是类类对象,用来“控制”模型和更新视图, 正如你所知,一切都是基于魔法和神秘 $scope property.

一个好的做法是避免将所有内容绑定到 $scope的监视列表中挤满了太多的绑定 $digest loop. 为了避免这种情况,Angular给了我们 controllerAs property.

Writing controllers as classes

Javascript中的类(至少目前在ES5中)是这样的:

var aClass = function () {
  this.name = 'Class name';
};
var instance = new aClass();

With this you can use the instance 变量来访问方法和属性.

Using the controllerAs 属性,我们用同样的方式编写控制器,使用 this instead of $scope

angular.module('myApp')
.控制器('MyCtrl', function () {
    this.name = 'Controller Name';
});

现在它可以在模板中实例化,如下所示:

要访问控制器的属性和方法,请使用 vm instance.

这样就为作用域设置了名称空间,使代码更清晰易读. Think about nested scopes.

{{ name }}
{{ name }}
{{ name }}

这里你可以看到每个控制器都在访问 name 财产,但问题是,哪一个? 这段代码看起来很混乱,可能是一个控制器优先于另一个控制器, but you don’t know which one.

Using the controllerAs 这样语法会清晰得多:

Base scope: {{ base.name }}
Section scope: {{ section.name }} Base scope: {{base.name}}
{{ final.name }}

正如我们在上面的代码中看到的,使用 controllerAs 语法允许我们访问父作用域,而没有作用域冲突的麻烦,也不用使用 $parent to access it.

How to set watchers

当您使用这种语法时,您会想到的一个问题是如何使用 $watch 打电话是因为你需要注射 $scope. We fight to remove the use of $scope现在无论如何我们都要注射它.

Well, we can keep using controllerAs 并将方法和属性绑定到 this 对象,该对象绑定到当前 $scope. 同时,我们可以保持关注点分离 $scope only for special cases, like $watch, $on, or $broadcast.

Keep in mind that using controllerAs the syntax for $watch method changes a little bit. 通常你会这样做:

app.控制器('Ctrl', function ($scope) {
    $scope.name = 'name';

    $scope.$watch('name', function (newVal, oldVal) {

    });
});

但现在不管用了,因为 $watch 是否在寻找监视属性 $scope,你不会直接绑定那个属性 $scope. 被监视的属性被绑定到 this. 现在正确的做法如下例所示:

app.控制器('Ctrl', function ($scope) {
    this.name = 'name';

    $scope.$watch(function () {
      return this.title
    }.bind(this), function (newVal, oldVal) {

    });
});

Alternative is using angular.bind:

app.控制器('Ctrl', function ($scope) {
    this.name = 'name';

    $scope.$watch(angular.bind(function () {
      return this.title
    }), function (newVal, oldVal) {

    });
});

How can I declare controllerAs 不使用DOM属性?

在指令的情况下,有 controllerAs 属性在指令签名中:

app.指令('指令',function () {
    return {
      restrict: 'EA',
      templateUrl: 'template.html',
      scope: true,
      controller: function () {},
      controllerAs: 'vm'
    }
});

Or for controllers in the $routeProvider:

app.配置(function ($routeProvider) {
  $routeProvider
  .when('/', {
    templateUrl: 'main.html',
    controllerAs: 'main',
    controller: 'MainCtrl'
  })
});

What Is One-Time Binding?

Angular 1.3引入了一个令人敬畏的新性能提升功能-一次性绑定. Angular官方文档是这样描述它的:

一次性表达式一旦稳定,将停止重新计算, 如果表达式结果是非未定义值,那么在第一个摘要之后发生什么.

So, how does it work?

Let’s remember the $digest cycle基本上是一个运行在Angular底层的循环,其中每个绑定的数据都被添加到观察者列表中. 循环检查列表中的更改, 当没有发现进一步的更改时结束, 然后触发DOM重新呈现.

When regular binding is used, 该属性被绑定到监视列表,并且永远不会从列表中删除. This makes the $digest 循环遍历所有绑定数据. The bigger the application, 更大的绑定和监视程序列表是, 最后,我们的 $digest is. With bigger loops, performances decrease, 在一个很大的代码库的情况下, 应用程序甚至可能变得无响应.

如前所述,从Angular 1开始.我们可以用新的一次性绑定语法声明一个值. Angular会在这个新值被定义后渲染它,并立即从观察者那里解绑定它. 类中的绑定数量 $digest loop will be reduced.

So, how can I use it?

它的语法非常简单:只需添加 :: 前面的任何值都将被视为一个 one-time binding.

通常你会这样做:


新的一次性绑定版本是这样的:


转换值不会改变,因此没有必要将其放在 $digest loop forever. 通过解除翻译值的绑定,我们提高了应用程序的性能.

Another use case is with ng-repeat,例如:

将从列表中解绑定项 ng-repeat 完成人口迁移,从我们的 $digest loop.

继续吧,升级到Angular 1.3 .试着改进你的应用.

Submit a tip

提交的问题和答案将被审查和编辑, 并可能会或可能不会选择张贴, 由Toptal全权决定, LLC.

* All fields are required

Toptal Connects the Top 3% 世界各地的自由职业人才.

Join the Toptal community.