强烈建议通读官方wiki文档,里面包含了FAQ,最佳实践,深入理解最核心的Directive及Scope等文章,

基础

1. 使用ng-repeat指令,为防止重复值发生的错误。加上track by $index。

<li ng-repeat="i in ctrl.list track by $index">{{ i }}</li>

2. 把控制器中与视图无关的逻辑都移到"服务(service)"中

3. 尽量要少操作DOM.这里有个简单的例子, 我们要做一个切换的按钮 (这个例子有点做作和有点长, 主要是为了表示一下很复杂的情况也是这样解决的.)

总结就是:

Don't wrap element inside of $(). All AngularJS elements are already jq-objects

Don't use jQuery to generate templates or DOM

这是官方阐明的

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

这个例子中有些错误, 第一,jQuery是不需要的. 第二即使其他地方引入了jQuery,我们还是可以用 angular.element 来替换. 第三, 即使要使用jQuery, jqLite (angular.element) 也会在引入jQuery时优先使用jQuery. 所以不要用$,而是angular.element. 第四, jqLite 不需要包裹$, 在link函数中,element 已经是一个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;
};
}
};
});

4. ng默认的解析标签是{{}},有时候会和其他模板引擎中的标签冲突,如Symfony的twig的模板。如要修改请使用 $interpolateProvider

var app = angular.module('myApp', []);
app.config(['$interpolateProvider', function($interpolateProvider) {
$interpolateProvider.startSymbol('{[');
$interpolateProvider.endSymbol(']}');
}]);

5. 重置form到初始状态,并清除之前的错误信息

// form.$setPristine()可以重置表单到dirty之前的状态,并且清除form上的ng-dirty类名
// accountForm是form元素的name属性值
$scope.accountForm.$setPristine();
$scope.accountForm.$setUntouched();

6. 有ng-if,没有ng-else,如果需要多条件判断,可以使用 ngSwitch

<ANY ng-switch="expression">
<ANY ng-switch-when="matchValue1">...</ANY>
<ANY ng-switch-when="matchValue2">...</ANY>
<ANY ng-switch-default>...</ANY>
</ANY>

7. 如何获取某dom元素上的scope信息,参见 调试的时候特别方便。

指令Directive

指令是angular.js的核心,用法及API请参见官方文档。指令中一个重要概念是scope的理解,这篇官方文章也非常好。

1. 本质上,当写 directive 时令时。当我们设置了 link 参数,实际上是创建了一个 postLink() 链接函数,以便 compile() 函数可以定义链接函数。编译函数(compile)负责对模板DOM进行转换。 链接函数(link) 负责将作用域和 DOM 进行链接。

....
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) { ... },
post: function postLink(scope, iElement, iAttrs, controller) { ... }
}
},
link: function postLink(scope, iElement, iAttrs) { ... }
...

个人理解compile函数的功能更强。

详情内容:[译]ng指令中的compile与link函数解析

2. directive中controller和link参数的作用差不多,区别是当需要暴露API给其他directive调用就使用controller,否则使用link。参见

3. directive动态加载不同的模板。 参见

angular.module("app", [])
.controller("DemoCtrl", ['$scope', function($scope){
let vm = this;
vm.data = [
{
fieldTypeId: 1,
title: 'first name'
},
{
fieldTypeId: 2,
title: 'this is text area'
}
]
}])
.directive('magicField', function(){
return {
template: '<div ng-include="contentUrl"></div>',
scope: {
fieldTypeId: '@'
},
replace: true,
link: function($scope, $element, $attrs){
let template = ''
if ($attrs.fieldTypeId == '1') {
$scope.contentUrl = 'tpl/input.html'
}
else if ($attrs.fieldTypeId == '2') {
$scope.contentUrl = 'tpl/textarea.html'
}
}
}
})

html

<body ng-app="app">
<div ng-controller="DemoCtrl as vm">
<div ng-repeat="field in vm.data">
<magic-field data-field-type-id="{{field.fieldTypeId}}"></magic-field>
</div>
</div>
</body>

4. 关于向父子controller中传递内容。

  • `$emit` 只能向parent controller传递event与data
  • `$broadcast` 只能向child controller传递event与data
  • `$on` 用于接收event与data

下面是一个例子有两个按钮Expand All和Collapse All。下面的蓝色框起来的都是一个一个Directive生成的组件。单击可展开和收缩。

点击Expand All可展开所有的组件

Expand All和Collapse All对应的方法是

        $scope.onExpandAllClicked = function () {
$scope.$broadcast('expand');
};
$scope.onCollapseAllClicked = function () {
$scope.$broadcast('collapse');
};

Directive内部

$scope.$on('expand', function () {
vm.expand = true;
});
$scope.$on('collapse', function () {
vm.expand = false;
});

SPA

1. 开发SPA单页应用时,当在路由中已经指定了controller,就要把html中的移除,比如`<body ng-app="7minWorkout" ng-controller="WorkoutController">`,否则会有两个controller,会出现加载两次的情况。

$routeProvider.when('/workout', {
templateUrl: 'partials/workout.html',
controller: 'WorkoutController'
});

性能及优化

1. 使用一次性绑定提高性能。尤其是在ng-repeat中

<p>Hello {{::name}}!</p>

<custom-directive two-way-attribute="::oneWayExpression"></custom-directive>

2. 由于html不是区分标签和属性大小写的,如h1和H1,浏览器都能正确的解析。为避免出现问题angular会normalizes (标准化) 元素的标签名和属性名。用了匹配正确的directive。

normalizes过程是:

  1. 移除元素/属性名字中开头的"x-"和"data-"

  2. 将以':','-'或'_'分隔的名字转换为驼峰.

如:

<div ng-controller="Controller">
Hello <input ng-model='name'> <hr/>
<span ng-bind="name"></span> <br/>
<span ng:bind="name"></span> <br/>
<span ng_bind="name"></span> <br/>
<span data-ng-bind="name"></span> <br/>
<span x-ng-bind="name"></span> <br/>
</div>

他们的效果是一样的,转换后最终都是用到的ngBind指令。

再来个例子

//定义directive
.directive('matchTables', function () {
return {
restrict : 'E',
scope: {
targetMatchesData: "=",
isTargetOwner: "<"
}, // 模版传参,注意大小写 <match-tables
is-target-owner="isTargetOwner"
target-matches-data="FormTargetData.Matches">
</match-tables>

3. 生产环境的优化。参见官网。 注意有一条通过下面的代码来禁用M和C的指令。这个是1.6.x之后的版本才生效。

$compileProvider.commentDirectivesEnabled(false);
$compileProvider.cssClassDirectivesEnabled(false);

4. 如果升级1.6后使用directive(为迁移NG2方便,官方建议写component),指令中绑定的变量报undefined。

需要加上

$compileProvider.preAssignBindingsEnabled(true);

具体升级指导:https://code.angularjs.org/1.6.0/docs/guide/migration

angularJs 技巧总结及最佳实践的更多相关文章

  1. 《AngularJS深度剖析与最佳实践》简介

    由于年末将至,前阵子一直忙于工作的事务,不得已暂停了微信订阅号的更新,我将会在后续的时间里尽快的继续为大家推送更多的博文.毕竟一个人的力量微薄,精力有限,希望大家能理解,仍然能一如既往的关注和支持sh ...

  2. 使用Unity3D的50个技巧:Unity3D最佳实践

    翻译故事 原文:http://devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/ 这篇技巧,我自己也在翻译, ...

  3. 《AngularJS深度剖析与最佳实践》笔记: 第二章 概念介绍

    第二章 概念介绍 2.1 什么是UI? 用户界面包括内容(静态信息+动态信息), 外观, 交互. 在前端技术栈中分别由HTML, CSS和JS负责. 进一步抽象, 分别对应于MVC三个主要部分: Mo ...

  4. 【转】45个实用的JavaScript技巧、窍门和最佳实践

    原文:https://colobu.com/2014/09/23/45-Useful-JavaScript-Tips,-Tricks-and-Best-Practices/ 目录 [−] 列表 第一次 ...

  5. 【转】超实用的JavaScript技巧及最佳实践

    众所周知,JavaScript是一门非常流行的编程语言,开发者用它不仅可以开发出炫丽的Web程序,还可以用它来开发一些移动应用程序(如PhoneGap或Appcelerator),它还有一些服务端实现 ...

  6. 45个实用的JavaScript技巧、窍门和最佳实践

    在这篇文章中,我将分享一组JavaScript的技巧.窍门和最佳实践,这些都是JavaScript程序员应该知晓的,不管他们是使用在浏览器/引擎上,还是服务器端(SSJS——Service Side ...

  7. 超实用的JavaScript技巧及最佳实践

    众所周知,JavaScript是一门非常流行的编程语言,开发者用它不仅可以开发出炫丽的Web程序,还可以用它来开发一些移动应用程序(如PhoneGap或Appcelerator),它还有一些服务端实现 ...

  8. 一些JavaScript的技巧、秘诀和最佳实践

    文章分享一些JavaScript的技巧.秘诀和最佳实践,除了少数几个外,不管是浏览器的JavaScript引擎,还是服务器端JavaScript解释器,均适用. 本文中的示例代码,通过了在Google ...

  9. 超实用的JavaScript技巧及最佳实践(上)

    在这篇文章中,作者将会向大家分享JavaScript开发的小技巧.最佳实践等非常实用的内容,不管你是前端开发者还是服务端开发者,都应该来看看这些小技巧,它们绝对会让你受益的. 文中所提供的代码片段都已 ...

随机推荐

  1. NETBEAN 启动报错 CANNOT LOCATE JAVA INSTALLATION IN SPECIFIED JDKHOME的解决办法

    打开 NetBeans 安装目录下的\etc目录,查找报错信息中的jdk字符串,修改netbeans.conf文件即可

  2. python 多进程、多线程

    1.多线程: 下面讲一个简单用法,这个模块比较简单,但是实际使用中会遇到很多坑 from multiprocessing import process def go(s): print "主 ...

  3. python基础学习14----正则表达式

    正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑. 在python中正则表达式被封 ...

  4. Linux之添加交换分区

    Linux下的交换分区我们可以随意改变大小,如果说日常生活中分区不够用,今天我们来举个例子如何添加. 1.首先是使用dd命令创建一个空文件,这个空文件的大小就是你要继续添加的swap的大小,比如我这里 ...

  5. python(set、dict)

    一.集合 它的元素是唯一的,并无序的. 1.集合定义 s = set() s = {1, 2, 3} 2.集合的方法 update版本的集合运算是在原集合上进行修改,返回值为None. add()表示 ...

  6. 【Alpha go】Day 2!

    [Alpha go]Day 2! Part 0 · 简要目录 Part 1 · 项目燃尽图 Part 2 · 项目进展 Part 3 · 站立式会议照片 Part 4 · Scrum 摘要 Part ...

  7. 关于react的一点工作总结

    首先,react是Facebook开发的一套前端框架,仅仅是MVC中的V.核心思想是“封装组件”,组件封装后可以作为一个独立的实体被引入到新的组件中,这样新的组件就又是一个实体了,由于组件的实现了可复 ...

  8. CSP vs Actor Go vs Erlang

    源于从Erlang到Go的一些思维碰撞,就像当初从C++到Erlang一样,整理下来记于此. Actor Actor模型,又叫参与者模型,其”一切皆参与者(actor)”的理念与面向对象编程的“一切皆 ...

  9. 协程运行原理猜测: async/await

    1.根据await调用链寻找最终的生产者或服务提供者: 2.请求服务: 3.进行执行环境切换,跳出顶层函数(第一个无await修饰的函数),执行后面的语句: 4.服务完成,将服务数据复制给最底层的aw ...

  10. HDU5629:Clarke and tree(DP,Prufer)

    Description Input Output Sample Input Sample Output Solution 题意:给你$n$个点,还有每个点的度数,问你任选$i(1\leq i \leq ...