2

angular

数据双向绑定的框架

提供数据绑定,DOM指令。angular,定义了一套规则,开发中就必须遵守规则,这套规则为项目提供了一套解决方案。

模块组件模板元数据数据绑定, 指令服务,依赖注入,控制器过滤器,路由

clipboard.png

基本概念

启动/引导

启动/引导 (Bootstrap)
作用:启动程序入口(bootstrap方法来引导Anuglar引用程序)
识别应用程序中的根作用域$rootScope
通过依赖注入体系注册服务的提供商

属性型指令

属性型指令 (Attribute Directive)
是指令分类的一种。
作用:监听或修改其它HTML元素,属性,组件的行为。一般作为HTML属性。
例如: ng-controller 当前所在的元素添加控制器。

组件

组件(Component)
作用:把数据展示到视图(view),并处理所有的视图显示和交互逻辑的Angular类。

在类中定义组件的应用逻辑 ( 它被用来为视图提供支持 ) , 组件通过一些由属性和方法组成的 API 与视图交互。

组件是Angular系统中最重要的基本构造核心之一。

clipboard.png

数据绑定

数据绑定(Data Binding)
作用:将数据展示给用户,用户操作做出应答。
将这些数据显示到HTML中,添加事件监听器,获取数据变化,更新数据。

clipboard.png

在双向数据绑定中,数据的属性值会从具有属性绑定的组件传到输入框。通过事件绑定,用户的修改数据传回到组件,把属性值设置为最新的值。

Anuglar 在每一个JS事件周期中一次性处理所有的数据绑定,它会从组件树的根部开始,用深度优先的方式! (数据绑定在模板与对应组件的交互中起到了重要作用)

clipboard.png

组件从技术角度上看就是一个指令。组件位置很独特,并在Angular中位于中心地位。

插值表达式

  • 属性绑定

  • 事件绑定

  • attribute绑定

  • css类绑定

  • 样式绑定

  • 基于ngModel的双向数据绑定

单向绑定 (ng-bind) 和双向绑定(ng-model)

ng-bind 单项数据绑定 ($scope -> view) 用于数据显示,简写形式 {{}}
区别:页面没有加载完毕{{val}} 会直接显示到页面,知道Angular渲染该绑定数据.
ng-bind则是在Angular渲染完毕后将数据显示.

ng-model 双向数据绑定 ($scope -> view and view -> $scope) ,用户绑定值会变化的表单元素等.

每次绑定一个东西到 view 上时 AngularJS 就会往 $watch 队列里插入一条 $watch,用来检测它监视的 model 里是否有变化的东西。

当浏览器接收到可以被 angular context 处理的事件时,$digest 循环就会触发。$digest 会遍历所有的 $watch 。

一次更新数据操作,至少会触发两次$digest() 循环,$gigest循环的次数达到了10次(超过10次后抛出一个异常,为了防止无限循环)

依赖注入

依赖注入(Dependency Injection)

需要依赖的原因:没法控制这实例背后隐藏的依赖。 当不能控制依赖时,类就会变得难以测试。

按需注入,需要才注入。
通过给函数添加形参,使得caller传入的参数的callee接收的参数逻辑分离,使得函数通过依赖管理系统仅仅需要声明需呀的协作对象,而不需要知道从哪里来,如何创建等问题。

依赖注入即是设计模式,同时又是一种机制:当应用程序的一些组件需要另外一些组件的时候,使用依赖注入机制来创建被请求的部件并将其注入到发出请求的组件中。

提供类的新势力的一种方式,负责处理好累所需的全部依赖。大多数依赖都是服务。Angualr使用依赖注入提供所需的组件以及组件所需的服务。

clipboard.png

angular构建应用程序时:定义许多精简的小部件,每个小部件只做一件事,并且做好它,然后在运行期把这写精简小部件装配在一起组成应用程序。

依赖注入的核心是:注入器(Injector),这个注入器根据需要返回被依赖的部件。injector.get(token) 方法返回与token(令牌)参数相关的依赖部件。

clipboard.png

令牌是一个Angular中类型.绝大多数类方法都接受类名或字符串。Angular会把这些类名称和字符串转换成令牌。当调用injector.get(Foo)时,注入器返回用Foo类生成的令牌所对应的依赖值,该依赖值通常是Foo 类的实例。

注入器(Injector)维护一个令牌与相应依赖值的对照表(map)。如果注入器不能找到一个令牌对应的依赖值,它就会使用提供商(Provider) 来创建一个依赖值.

提供商是创建依赖实例的“菜谱”之一,这个实例会与一个特定的令牌关联起来。

只有当注入器内部的提供商注册表中存在于令牌对应的提供商时,注入器才能为这个令牌创建一个依赖值。

angular会为每个注入器注册很多angular内建提供商。
通常注册提供商的最佳时间是在应用程序引导(Bootstrap)的时候。

依赖注入渗透在整个框架中,并且被到处使用。
注入器负责维护一个 容器 ,用于存放它创建过的服务实例。
注入器能使用 提供商 创建一个新的服务实例。
提供商 是一个用于创建服务的“配方”。
把 提供商 注册到注入器。

指令

指令(Directive)
指令是一个Angular类
作用:创建和重塑浏览器DOM中的HTML元素,负责与HTML元素的应答系统

指令包括的类别:

  • 组件(Component): 用来把程序逻辑和HTML模板组合起来,渲染出应用程序的视图。组件一般表示成HTML元素的形式,

  • 属性型指令:可以监控和修改其它HTML元素,HTML属性,DOM属性,组件等行为。

  • 结构性指令:负责塑造HTML布局。一般是通过添加,删除或操作HTML元素及其子元素来实现的。

注入器

注入器(Injector)
Anuglar依赖注入系统中的一个对象。
作用:从缓存中找到一个"有名字的依赖"或者利用一个已注册的提供商来创建依赖。

注入器是一个维护服务实例的容器,存放着以前创建的实例。
如果容器中还没有所请求的服务实例,注入器就会创建一个服务实例,并且添加到容器中,然后把这个服务返回给Angular。
当左右服务都被解析并返回时,Angular会以服务为参数去调用组件的构造函数。

插值表达式

插值表达式(Interolation)

属性数据绑定的形式:位于双大括号中的模板表达式会被渲染成文本。

模块

模块(Module)
应用程序通常由很多个模块组装而成。
模块导出东西--类,函数,值,供其它模块引入。
把应用写成一组模块,每个模块只导出一样东西。

clipboard.png

模块:具有单一用途的内聚代码块

一个模块加载器来按需加载模块并解析模块的依赖关系。

模块库

clipboard.png

有些模块是其它模块的库
Anuglar 本身就是通过npm包发布的一组模块库, 以@angular为前缀。
每个库包含一个 封装桶 。是公开的外观层(facade) 包括一些逻辑相关的私有模块。

管道

管道(Pipe)

管道是一个函数
作用:把输入值换成输出值供视图显示。

提供商

提供商(Provider)
作用:依赖注入系统依靠提供商来创建依赖实例。
它把一个供查阅用的令牌和代码关联到一起,以便创建依赖值。

服务

服务是一个类,具体实现一件事情,具有专注,良好定义的用途。
几乎任何东西都可以是一个服务。

clipboard.png

结构型指令

添加,删除或操作元素和其各级子元素来塑造或重塑HTML布局的指令。

例如:ngIf

模板

模板(Template)
模板是大块HTML。
作用:渲染视图
Angular会在指令和组件的支持和持续指导下,渲染视图。

clipboard.png

装饰器

装饰器 (Decorator | Decoration)

装饰器是一个 函数,这个函数将元数据添加到类,类成员(属性,方法)和函数上。

angular 使用自身一套装饰器来实现应用程序各个部分之间的相互操作。

基础指令

ng-app

应用程序的指令,一个程序中必须要有该指令

<body ng-app></body>

ng-model

数据绑定的指令,将数据绑定到应用程序中

<input type="text" ng-model="msg" />

ng-bind

绑定数据,它的简写方式直接在元素中{{key}}


<div>{{ msg }}</div>

当页面加载完毕,angularjs启动起来,首先回去页面中寻找ng-app指令,找到后初始化应用程序。
ng-app告知angular这个应用是绑定那个DOM元素,也就是程序初始化的元素时body,所以以后绑定的指令能够生肖的只能在ng-app所在的元素中
angularjs找到ng-model指令,它将该指令对应数据绑定在该程序的作用域中。
angularjs找到ng-bind或者{{key}} 指令,它将数据渲染到该元素内。
angularjs遍历其它指令,完毕后,就可以使用应用程序。

ng-init

表示初始化应用程序中的变量,多个变量用; 注意定义多个变量不能用逗号,只能用分号;

<div ng-init="msg='hello wrold'; info='您输入的信息为:'" ng-controller="msg">
    <input type="text" name="" id="" value="" ng-model="msg" />
    <span ng-bind="msg"></span>
    <span>{{ info }}</span>
    <span>{{ msg }}</span>
</div>

module

通过angular.module方法
该方法有两个参数
参数1,表示程序的名称。
参数2,表示依赖服务(依赖集合)
依赖就是达到某个目的的必要条件(不可或缺)。

var app = angular.module('app', []); 

controller控制器

定义控制器
App的controller方法:
两个参数
第一个参数表示控制器的名称
第二参数表示控制器的构造函数
参数是你需要的数据,需要什么可以传递什么,这样在构造函数中就可以使用它,如果没有传递就无法使用
ng-controller 控制应用程序的,后期对某一视图动态改变的作用

定义控制器
app.controller();
参数1:控制器名称
参数2:控制器的回调函数(构造函数)
回调函数的参数是所需要的数据,需要什么可以传递什么,这样在回调函数中就可以使用它,如果没有传递就无法使用

angular参数注入:想用什么东西就在参数中注入。

  • 不要再控制器中操作 DOM。 通过指令完成。

  • 通过控制器完成的功能命名控制器,并以字符串Ctrl结尾,例如:(HomePageCtrl)

  • 控制器不应该全局中定义


  • 尽可能精简控制器,将通用函数抽线为独立的服务

  • 通过方法引用进行跨控制器通讯(通常是子控制器与父控制器通讯) 或者 $emit,$broaadcast 以及 $on 方法。发送或广播的消息应该限定在最小的作用域。

  • 置顶一个通过 $emit,$boradcast 发送的消息列表并且窒息的管理以防止命名冲突

  • 在需要格式化数据时,将格式化逻辑封装成 过滤器

<div ng-controller="msg"></div>

// 控制器
app.controller('msg', function ( $scope ) {
    
    console.log( this );
    console.log( arguments );
    
});

控制器$scope

$scope: 用来实现数据与视图的连接,在$scope上定义的数据,可以用视图在上,那么视图上绑定的数据可以在$scope上也能获取到

$scope 是通过原型式继承实现, 子作用域会继承父作用域中的变量,但是可以为子作用域添加变量还重写符作用域中的变量。

scope特点

  • $scope 是一个 POJO 简单的Java对象

  • $scope 提供了一些工具方法$watch()/$apply();

  • $scope 表达式执行环境,或者说作用域

  • $scope 是一个树型结构,与DOM标签平行

  • 每一个angularjs应用都有一个跟作用域$rootScope,位于ng-app上

  • $scope 可以传播事件,类似DOM事件,可以向上下可以向下

  • $scope 不仅是MVC 的基础,也是后买呢实现双向绑定的基础,应用开始先找rootScope,然后把下级scope附加到rootScope上从而形成树型结构.

clipboard.png

scope生命周期

创建(creationd)

在创建控制器或指令时,angularjs会用$onjector创建一个新的作用域,并在这个新建的控制器或指令时把作用域传进去

链接

scope对象会附加或链接到视图。这些作用域将会注册到 angular上下文中发生变化时需要运行的函数
$watch -> 注册监控(Watcher registration) 变化时执行 回调函数

更新

事件循环执行时,顶级的$rootScoep和每个子作用域都执行自己的脏值检查。某个监控函数监控变化,检测到变化后,$scope会触发指定的回调函数。

销毁

当scope在视图中不再需要时,会清晰和销毁自己。
$scope.$destory();

events

ng-eventsName
例如:ng-click
如果想在回调函数中传递参数,在圆括号里面直接添加

执行的作用域是$scope,当前的作用域
参数通过元素调用时传递的参数一致,最后一个参数为事件对象

<button ng-click="clickBtn('info',$event)" ng-bind="red"></button>

// 事件
$scope.clickBtn = function ( msg, ev ) {
    
}

显隐

ng-show 表示显示元素指令
ng-show 显示元素:true显示,false隐藏
ng-hide 隐藏元素:true隐藏,false显示

<span ng-show="isShow">1</span>
<span ng-hide="isShow">2</span>

表达式

插值和数据的过程中可以应用表达式
的绑定过程我们可以应用表达式
在表达式中不仅仅可以用运算符,还可以应用js提供的方法

<div>{{'面积是:' + width * height}}</div>

<div>{{ msg.toUpperCase() }}</div>

过滤器

用来对绑定数据显示时候处理
{{key | filter}}

内置过滤器

currency
格式化数字为货币格式

<div>{{msg | json}}</div>
<div>{{ msg | currency }}</div>

filter
过滤数组项

<div ng-controller="filters">
    <div>{{ color | filter : 'n' }}</div>
    <div>{{ color | filter : filterChar }}</div>
    <div>{{ color | filter : filterFirstStr }}</div>
</div>

<script type="text/javascript">
    
    // app 
    var app = angular.module('appBody', []);
    
    // controller 
    app.controller('filters', function ( $scope ) {
        
        $scope.color = ['tan', 'khaki', 'Pink', 'cyan'];
        
        // a 过滤出来
        $scope.filterChar = 'a';
        
        $scope.filterFirstStr = function ( val ) {
            
            // 匹配首字母大写
            return val[0] === val[0].toUpperCase();
            
        }
        
    });
    
    
</script>

date
日期过滤器,格式化日期

<div ng-controller="dates">
    <span>{{ iDate | date : 'yyyy' + '年'}}</span>
    <span>{{ iDate | date : 'MM' + '月' }}</span>
    <span>{{ iDate | date : 'dd' + '日' }}</span>
    <span>{{ iDate | date : 'HH' + ':' + 'mm' }}</span>
    <p>{{ iDate | date : 'yyyy年 MM月dd日 HH:mm' }}</p>
</div>

// app 
var app = angular.module('appBody', []);

// controller 
app.controller('filters', function ( $scope ) {
    
    $scope.color = ['tan', 'khaki', 'Pink', 'cyan'];
    
    // a 过滤出来
    $scope.filterChar = 'a';
    
    $scope.filterFirstStr = function ( val ) {
        
        // 匹配首字母大写
        return val[0] === val[0].toUpperCase();
        
    }
    
});

limitTo
截取过滤器
参数表示截取的长度
这个过滤器不仅仅可以截取字符串,还可以截取数组

<div>{{ color | limitTo : 2 }}</div>

<div>{{ msg | limitTo : 3 }}</div>

字符串大小写
uppercase 将字符串转化成大写
lowercase 将字符串转化成小写
这个过滤器痛对数据直接调用字符串方法toUpperCase和toLowerCase效果是一样的
但是angular建议使用过滤器
过滤器可以被复用
不建议在表达式中使用方法(除特殊情况)

<div>{{ msg | uppercase }}</div>
<div>{{ msg | lowercase }}</div>
<div>{{ msg.toLowerCase() }}</div>

number过滤器
是一种数字类型数据过滤器
参数表示截取小数位置
该过滤器是将数字以每三为分割渲染的
不传递参数默认保留三维,最后一位四舍五入

<div>{{ num | number }}</div>
<div>{{ num | number : 4 }}</div>

orderBy
对数组进行排序的过滤器
参数1,数组中每个成员排序的索引属性名称
参数2,正序还是倒序 (true反序)

<div>{{ color | orderBy : '' : true }}</div>
<div>{{ color | orderBy }}</div>

自定义过滤器

定义
通过app提供的filter方法来定义过滤器 app.filter();接受两个参数
参数1,过滤器的名称
参数2,过滤器的回调函数(构造函数)
回调函数必须返回一个函数,这个函数在每次数据更新时候执行。
回调函数只执行一次
返回的函数,可以接受过滤器使用时传递的参数,但是第一个参数永远是绑定的数据,后的参数才是传递的参数,参数的顺序痛使用时传递参数的顺序一致。

调用
使用方式同内置过滤器一样,在管道符号后面添加过滤器的名称,通过添加参数

  • 使用小驼峰命名

  • 尽可能使过滤器精简。 过滤器在 $digest loop 中频繁被调用,过于复杂的运算使得整个应用执行缓慢。

  • 在过滤器中只做一件事. 更加复杂的操作可以用pipe来实现.

    <!--自定义过滤器-->
    <input type="text" ng-model="msg" />
    <div>{{ msg | CaseChar }}</div>
    <div>{{ msg | CaseChar : true }}</div>    
    
    

app.filter('CaseChar', function () {
    
    return function ( val, FirstToUpper ) {
    
        if ( val ) {
            
            // FirstToUpper 参数 表示第一个字母大写
            if ( FirstToUpper ) {
                
                // 第一个字母 大写
                val = val.replace(/^[a-z]/, function ( match, $1 ) {
                    
                    return match.toUpperCase();
                    
                });
                
            }
            
            // 存在输入的val 值   转驼峰
            return val.replace(/_([\w])/g, function ( match, $1 ) {
                
                return $1.toUpperCase();
                
            });
            
        } 
        
        return '';
        
    }
    
});

表单验证

当对表单元素form添加name属性时候,angular会自动将该属性的值添加到作用域中,并且该属性具有表单验证的属性. 具有FormContorller对象

$dirty 表单是否被用户输入过,输入过,值为true,没有输入过值为false
$pristine 表单是否被用户输入过,输入过,值为false,没有输入过值为true
$valid 输入的值是否合法,合法值为true,不合法为false
$invalid 输入的值是否合法,合法值为false,不合法为true

$valid 属性值为true时,所有表单元素必须$valid都是true
$invalid 属性为true时,只要有一个表单元素$invalid之为true
$dirty 属性为true时,只要有一个表单元素被修改过,$dirty值为true
$pristine 属性为true时,所有的元素未被修改过,那么$pristine值为true

<form name="appForm">
    
    <label for="">用户名:</label>
    <input type="text" name="username" ng-model="uname" ng-maxlength="5" id="" value="" />
    <span ng-show="appForm.username.$invalid">输入的长度大于5</span>
    
</form>   

<form name="appForm">
    
<!-- 兼容 HTML5 表单元素 -->
<label for="">邮箱:</label>
<input type="email" name="emial" ng-model="emailModel" id="" value="" />
<span ng-show="appForm.emial.$invalid">输入内容必须是emial</span>
    
</form>

<form name="appForm">
    
<!--使用 ng-pattern 匹配正则-->
<input type="text" name="txt" ng-model="passModel" ng-pattern="/^\d{4,6}$/" id="" value="" />
<span ng-show="appForm.txt.$invalid">输入的内容必须是4-6位数字</span>
    
</form>

run-$rootScope

获取app并执行(程序入口指令会提供一个run方法),通常会在该方法中访问根作用域,该方法接收一个函数作为参数,
函数中的this指向window,因此可以访问到全局作用域下的变量。
arugments默认没有值,需要什么值,需要通过参数注入来供函数内使用。
作用:处理的是根作用域,因此通常要将$rootScope传递进来.

app.run(function ( $rootScope ) {
});

controller与作用域

var app = angular.module('main', []);

app.controller('parentCtrl', function ( $scope ) {
    
    $scope.clickParent = function () {
        
        $scope.msg = 'parentScope';
        
        
    }
    
}).controller('childCtrl', function ( $scope ) {
    
    $scope.clickChild = function () {
        
        $scope.msg = 'childScope';
        
    }
    
});

// rootScope
app.run(function ( $rootScope ) {
    
    $rootScope.msg = 'rootScope';
    
})

console.log( app );

ng指令

ng-disabled
表单是否可以操作

<input type="text" ng-disabled="isable" name=""  />

ng-readonly
表单是否是只读

<input type="text" ng-readonly="isable" name="" id="" value="" />

ng-checked
选择框是否被选中
值为true:选中
值为false:未选择

<input type="checkbox" ng-checked="isabel" name="" id="" value="" />

ng-change
监听输入表单内容的改变,当表单内容改变的时候就会触发.
改变的时候,需要知道数据是否更改,需要加上ng-model

<input type="text" ng-model="msg" ng-change="change()" name=""  />    

app.controller('inp', function ( $scope ) {
    
    $scope.change = function () {
        
        alert($scope.msg);
        
    }
    
});

ng-submit
对form表单元素绑定submit事件,当点击表单中submit元素时候,会触发该事件
ng-submit需要搭配标签form使用

<form name="forms" ng-submit="submit()">
    
    <input type="text" name="" ng-model="msg" id="" value="" />
    
    <input type="submit" value="提交"/>
</form>

ng-src
浏览器打开页面,浏览器不认识ng-src属性,所就不会发请求,那么当ng-src绑定的数据imgSrc有数据的时候,angular会把这个数据赋值给src属性,让img标签发送一个请求

<img ng-src="{{imgSrc}}" />

ng-href
当浏览器打开页面的时候,元素不具有href属性,就不具有链接行为(为#号却能够点击),ng-src对这一现象做了优化,当ng-href绑定的数据加载成功后,将这一属性值,赋值给a标签的href属性,让a标签具有连接的行为。

<a ng-href="{{Url}}">跳转</a>

ng-class
是用来动态创建类的一个指令,它的只是一个对象,对象中的舒心代表类的名称,属性值只能是一个Boolean
true,会将该类名添加到元素的class属性中。
false,会将该该类名从该元素的class属性中删除。

<div ng-class="{red: ngClassInfo>4, green: ngClassInfo <=4 }">{{ ngClassInfo }}</div>

ng-style
用来动态创建样式,它的值是一个对象,对象中的属性表示css属性,值为css属性值。

<div ng-style="{background: 'tan', width: '100px', height: '100px'}"></div>

ng-if
判断指令.
angular中没有ng-else指令,可以通过ng-if模拟

<div ng-if="isable">111111111111</div>
<div ng-if="!isable">222222222222</div>

ng-switch
分支判断
当元素这是了ng-switch,元素是一个ie分支判断的模板,所有分支都要包含在该元素内。
通过on指令来设置判断条件,ng-switach和on配合使用
ng-switch-when="key":表示判断某一条件,当on的绑定的数据值为该分支对应的值的时候,执行。

<!--需要将分支判断的元素放入 ng-switch 容器中-->            
<div ng-switch="" on="switchInfo">
    
    <div ng-switch-default="">默认</div>
    <div ng-switch-when="first">1111</div>
    <div ng-switch-when="second">2222</div>
    
</div>

ng-repeat
循环渲染模板
语法: ng-repeate="item in list";
内置变量
$index 循环的索引值,从0开始计数
$first 第一次循环是true,其它次循环是false
$last 最后一次循环是true,其它此循环是false
$middel 除去第一次和最后一次值是true
$even 偶数次循环是true,奇数次循环是false
$odd 奇数次循环是true,偶数次循环是false

<ul>
    <li ng-repeat="item in colors" ng-class="{red: $odd}">{{ item }} --- {{'索引值:'+$index}} --- {{ $middle }}</li>
</ul>

ng-include
模板定义在单独文件中,通过ng-include引入进来.
ng-include="url" 注意url是字符串

<div ng-controller="aMsg">
    
    <div ng-include="'a.html'"></div>
        
</div>

// 数据传输
var aMsgApp = app.controller('aMsg', function ( $scope ) {
    
    $scope.msg = '载入成功';
    
});
  • 使用 ng-bind 或者 ng-cloak 而 不是使用 {{}} 插值方式,防止页面渲染闪烁

  • 避免在插值中使用复杂代码

  • 需要动态设置 <img> 的 src 时使用 ng-src 而不使用 src中嵌套 {{}}

  • 需要动态设置 <a> 的 href 时使用 ng-href 而不是用 href 中嵌套 {{}}

  • 通过对象参数和scope变量作为值来使用 ng-style 指令, 而 不是使用 scope 变量作为字符串通过 {{}} 用于 style 属性。

自定义指令

directive();

参数1: 指令的名称
参数2: 构造函数,自定义指令式,只执行一次,将一些复杂业务逻辑放在该函数中,最后改函数返回是一个对象(用来描述指令)

规则:

  • 使用小驼峰命名。

  • 在link function 中使用 $scope 。 在compile中, 定义参数的post/pre link functions 将在函数执行时被传递,无法通过依赖注入改变它们。

  • 指令添加自定义前缀避免与第三方指令冲突

  • 可复用组件创建独立作用域

  • 使用 scope.$on('$destroy', fn) 来清除. 这点在使用第三方指令的时候特别有用.

返回对象

restrict: 自定义指令的类型
E,该指令是一个自定义元素(element)
A,该指令在元素时属性上(attributes)
C,该指令在元素的类上(class)
M,注释指令(comment)

template: 传递的是模板字符串

templateUrl: 模板文件的路径

replace: false
是否替换原有的元素,true会替换掉原有的元素,false不会替换掉元素。
当设置true时,会对controller中使用的参数$element 和 $attrs 有影响

controller
用来定义自定义指令的作用域。
this 指向的controller{}空对象
arguments默认情况下是一个空数组,需要参数注入。
$scope 该指令的作用域
$element 该指令的元素
$attrs 该指令的元素的属性

// directive() 自定义指令
app.directive('curtoms' , function () {
    
    console.log(111);
    
    return {
        
        // 指令类型
        restrict: 'EAC',
        
        // 模板字符串
//                    template: '<h1>自定义指令</h1>',
        
        // 模板文件获取 url
        templateUrl: 'a.html',
        
        // replace表示是否替换原来的元素,true是替换,false不替换
//                    replace: false,
        replace: true,
        
        controller: function ( $scope, $element, $attrs ) {
            
            // this 指向 controller{} 空对象
            
            console.log( $scope, $element, $attrs );
            
        }
        
    }
    
});

scope
隔离自定义的作用域的属性,通过对其社会字一个对象来隔离指令的作用域。
如果值是true或者false,指令的作用域就会忽略自身作用域,而去寻找父级作用域中的变量。
如果值是空对象{} ,作用域会指向该空对象

directive返回对象中的scope和controller
自定义指令中,scope属性对controller的影响:
如果scope的值是true,在controller中,定义与父作用域中相同变量时,自定义指令中的变量不会受到副作用于中的变量的影响。
如果scope是一个false,在controller中,定义与父作用域相同变量时,该变量与父作用域中的变量同步(同时修改,数据双向绑定)
如果scope是一个对象,在controller中,定义与父作用域相同的变量时,自定义指令中的变量不会收到父作用域的变量影响。

app.directive('myCutom', function () {
    
    return {
        
        restrict: 'E',
        
        template: '<h1>{{ msg }} -- {{ title }}</h1>',
        
        // scope: {},
        // scope: true,
            scope: false
        
        controller: function ( $scope, $element, $attrs ) {
            
            $scope.title = 'aaaa';
            
            $scope.msg = 'xixixi';
            
        }
        
    }
    
});

@修饰符
可以屏蔽模板中变量去controller作用域中寻找值的过程,而是让其去该自定义指令所在元素的属性中寻找数据变量. 忽略自定义指令的scope。
@修饰符会去自定义指令中所在元素的属性去寻找。
属性值是插值传入,作为普通属性处理。

<my-custom my-title="{{title}}"></my-custom>

app.directive('myCutom', function () {
    
    return {
        
        restrict: 'E',
        
        template: '<h1>{{ msg }} -- {{ title }}</h1>',

        scope: {
        // 告知 自定义指令 不需要从 自己的作用域中寻找 变量
            title: '@myTitle'
        },

        controller: function ( $scope, $element, $attrs ) {
            
            $scope.title = 'aaaa';
            
            $scope.msg = 'xixixi';
            
        }
        
    }
    
});

=修饰符
通过在scope属性中定义含有=修饰符的变量时,可以取得父作用域中的变量,通过属性映射.

作用:自定义指令作用域中变量与父作用域的双向绑定过程.
注意:自定义元素中的属性值是一个父作用域中的一个变量,在自定义指令中当作一个变量来处理。

template,中的数据和 父级的作用域$scope,数据绑定

tempalte: '<h1>{{title}}</h1>',


app.controller('main', function ( $scope ) {
    $scope.title = '';
});

link

操作自定义指令的DOM

link的函数
this指向window
arguments:
1 scope, 指令作用域
2 jqlite 获取自定义元素
3 attrs 自定义指令元素上的属性

// 操作自定义指令元素
// @param {Object} scope  子作用域
// @param {Object} jqlite JQ对象
// @param {Object} attrs 自定义上的属性
link: function ( scope, jqlite, attrs ) {
    
    // this -> window
    var el = jqlite.children('h1').attr('nodeValue', 1);
    
    // 使用 data 自定义属性  ,会自动省略  data-
    
    for ( var i=0; i<attrs.repeate; i++ ) {
        
        jqlite.append( el.clone() );
        
    }
    
}

complie

this指向的是指令描述对象.
参数1: jqlite 获取的自定义元素
参数2: attrs 自定义指令所在元素的属性
返回一个函数, 指向 link 函数
在返回函数中,可以操作自定义指令所在元素.

<div ng-controller="main">
    
    <my-directive data-color="pink">
        <h1>嘻嘻哈哈</h1>
    </my-directive>
    
</div>

<script type="text/javascript">
    
    // 创建 app
    var app = angular.module('app', []);
    
    // 创建控制器
    app.controller('main', function ( $scope ) {});
    
    // 自定义指令
    app.directive('myDirective', function () {
        
        return {
            
            restrict: 'E',

            // 自定义指令的编译方法
            // @param {Object} jqlite  获取自定义指令元素
            // @param {Object} attrs   自定义指令所在元素上的样式
            // @return {Function} cb   指代 link 
            compile: function ( jqlite, attrs ) {
                
                // this -> compile 对象 
                
                return function ( scope, jqlite, attrs ) {
                    
                    // this -> window
                    var color = attrs.color;
                    
                    jqlite.css('color', color);
                    
                }
                
            }
            
        }
        
    });
    
</script>

transclude

它告诉自定义指令,要将自定义元素中未知的元素内容插入到已知模板具有ng-transclude指令所在的元素中(添加自定义指令元素中的未知元素)
未知元素:自定义标签中的元素.

告知自定义指令,要将自定义中未知的元素内容插入到已知模板。
条件: 模板标签上具有ng-transclude指令
需要设置 transclude: true.

现象:模板标签会包裹自定义标签内的内容.

app.directive('myDirective', function () {
    
    return {
        
        restrict: 'E',
        
        template: '<div ng-transclude></div>',
        
        transclude: true    
        
    }
    
});

require

自定义指令引用其它指令,作为link()方法的第四个参数.
例如,将ngModel引入到自定义指令中. 在link方法中可以访问到ngModel中的属性值

require: 'ngModel'

// 自定义指令
app.directive('myDirective', function () {
    
    // 返回一个描述指令对象
    return {
        
        restrict: 'A',
        
        // 引入其它指令
        require: 'ngModel',
        
        link: function ( scope, jqlite, attrs, ngModel ) {
            
            // $watch 检测某个值 发生改变,触发某个函数
            // 当 ngModel 值发生改变, 触发函数
            scope.$watch(attrs.ngModel, function () {
                
                console.log(ngModel.$viewValue);
                
            });
            
        }
        
    }
    
});

服务

对一些方法的封装,复用方法更为简便。例如:消息系统,作为消息服务.
使用服务,利用参数注入即可。

  • 大驼峰和小驼峰都可

  • 将业务逻辑封装成服务

  • 将业务逻辑封装成 service 而非 factory

  • 使用 $cacheFactory 进行绘画级别的缓存。 应用于缓存请求或复杂运算的结果。

内置服务

$timeout
对setTimeout()的封装

app.controller('main', function ($scope, $timeout) {

    $timeout(function () {

        console.log(this);
        console.log(arguments);
        
    }, 2000);

});

$interval
对setInter();的封装

app.controller('main', function ($scope, $interval) {
    // 定义一个时间
    $scope.date = new Date();

    $interval(function () {
        // 重新定义日期
        $scope.date = new Date();
    }, 1000);

});

$http
异步请求

配置参数:
method: 请求方式 "GET","POSt"
url: 请求的地址
$http 方法执行完后链式调用success(),请求成功的回调函数

POST请求:
通过设置data属性添加POST请求发送数据
params属性添加请求的参数数据

// $http 服务
$http({
    method: 'GET',
    url: 'data/service.json'
}).success(function ( res ) {  
    
    if ( res.errno === 0 ) {
        
        $scope.msg = res.msg;
    
        console.log(res);
        
    }
    
});

$http({
    method: 'POST',
    url: 'demo.json',
    // 该属性会将键值对转化成url上参数
    params: {
        id: 11
    },
    // post请求 添加请求数据
    data: {
        username: 'aa'
    }
});


$http.get,$http.post
$http服务中的get请求和post请求简写方式
params 配置请求参数

// get 请求
$http.get('data/service.json', {
    params: {
        id: 1
    }
})
// 请求成功
.success(function ( res ) {
    
    console.log( res );
    
});

// post 请求
// 参数1:url ,参数2:请求携带的数据
$http.post('data/service.json', {
    id: 1
})
// 请求成功
.success(function ( res ) {
    
    console.log(res);
    
});
 

promise对象
允诺对象,在内部是一个异步操作,当操作完成时,这个对象会实现它的允诺.
特点: 可以无限添加允诺。 一定在某些操作完成时才出发。
规范中允诺对象使用 then方法.

自定服务

需要各种服务以支持各种功能,也可以手动开启或关闭某些服务以达到相应的功能.

factory()
工厂模式定义自定义服务
参数1:服务名称
参数2:服务工厂方法
返回值:服务对象,这个对象提供其它控制器使用

var app = angular.module('app', []);

// 其它控制器使用服务
app.controller('facotryCtrl', function ( $scope, news ) {
    
    $scope.msg = news.data;
    
});

// factory 定义 服务
app.factory('news', function () {
    
    return {
        data: '嘻嘻哈哈'
    }
    
});

service

面向对象创建服务
参数1:服务名称
参数2:服务的构造函数(构造函数中需要使用this来暴露接口)

// 使用 service 自定义服务
app.service('data', function () {
    
    this.title = '嘻嘻哈哈';
    
});

路由

使用组件配合使用:
angular-route.js
angular-ui-router.js
用来寻找页面,通常通过配置一些路由来映射一些页面

路由:就是URL到函数的映射

ngRoute

需要在程序入口处引入,添加到依赖集合中

angualr.module('app', ['ngRoute']);

ng-view

动态渲染的视图,视图如何渲染根据路由决定

<div ng-view></div>

渲染视图需要在页面初始化之前知道路由配置.
使用congfig();

congfig();
在应用程序执行之前执行一个配置方法,在页面还未被渲染,可以将路由逻辑放入该方法中。
回调函数:
this -> window
默认参数是空的,需要将服务注入

// 配置
app.config(function ( $routeProvider ) {

$routeProvider.when('/', {
    
    // 模板
// template: '<div>嘻嘻哈哈</div>',
    templateUrl: 'a.html',
    
    // 控制器
    controller: function ( $scope ) {
        
        console.log( $scope );
        
        $scope.style = {
            color: 'deeppink'
        }
        
    }
    
});

$routeProvider
路由服务:
路由供给服务,提供一个when方法,供使用配置路由.

controller
在路由对象中,可以通过controller属性,为路由对象添加控制器,创建一个作用域,让模板可以使用作用域中的变量。

template
配置模板字符串

templateUrl
配置外部模板
会发送异步请求

otherwise
重定义路由
配置两个路由以上,otherwise 才会有效果.
配置参数为 redirectTo 来重定向到不同路由,值是定义过路径.

// app
var app = angular.module('app', ['ngRoute']);

// controller
app.controller('routerCtrl', function ( $scope ) {
    
    $scope.shop = 'shopPage1';
    
});

// config
app.config(function ( $routeProvider ) {
    
    // 配置首页 路由  
    $routeProvider.when('/', {
        
        template: '<h1>{{ index }}</h1>',
        
        controller: function ( $scope ) {
            
            $scope.index = 'indexPage';
            
        }
        
    })
    
    // 配置  shop 页面 路由
    .when('/shop', {
        
        template: '<h1>{{ shop }}</h1>',
        
        controller: function ( $scope ) {
            
                //    $scope.shop = 'shopPage';
            
        }
        
    })
    
    // 其它路由 重定义 到  / 目录中
    .otherwise({
        redirectTo: '/'
    });
    
});

路由参数

路由路径配置参数(参数名前需要加:冒号)
将获取路由参数服务注入控制器中($routeParams注入控制器中).

app.config(function ( $routeProvider ) {
    
    // 配置参数
    $routeProvider.when('/shop/:pageNum/:type', {
        
        template: '<h1>{{ shop }}</h1>',
        
        // 参数注入
        controller: function ( $scope, $routeParams ) {
            
            $scope.shop = 'shopPage';
            
            console.log( $routeParams );
            
        }
        
    });

});

路由时间
路由时间通常定义需要监听该事件的控制器中,在全局作用域下监听,通过对作用域$on()方法监听路由事件。
例如:$routeChangeSuccess
监听路由改变成功
参数1: 表示事件对象
参数2:表示当前路由对象
参数3:表示前一个路由(如果当前没有前一个路由对象,因此参数会是undefined)

app.run(function ( $rootScope ) {
    
    $rootScope.$on('$routeChangeSuccess', function ( ev, routeObj, preRouteObj ) {
        
        
    });
    
});

$location
管理地址栏状态信息,包括query,path
path(): 改变路由中的path.
读:$location.path();
设:$loction.path(arg);

app.run(function ( $rootScope, $location ) {
    
    $rootScope.$on('$routeChangeSuccess', function ( ev, routeObj, preRouteObj ) {
        
        // var q = $location.path(); // 读
        
        $location.path('/xixi'); // 设置  
        
    });
    
});

ui-router

ngRoute: 每个页面对应一个地址(path), 需要渲染那个页面,就需要配置路由.
uiRouter: 引入state(状态)概念,如果哪个页面如果显示,渲染出对应的页面,渲染之后会有一种状态,可以将该状态记录,配置路由

ui-view

在ui-router 中使用的指令ui

<div ui-view=""></div>

$stateProvider
参数注入到config()来定义状态


app.config(function ( $stateProvider ) {});

state();
定义状态
参数1:状态名称
参数2:配置参数
url: 状态页面的地址
tempate: 状态对应页面的模板
controller 定义状态对应页面的作用域


// 参数注入 ui.router
var app = angular.module('app', ['ui.router']);

// 配置路由
app.config(function ( $stateProvider ) {

// $stateProvider 定义状态
console.log( $stateProvider );

$stateProvider.state('home', {
    
    // 配置 #/
    url: '/',
    
    template: '<h1>{{ indexPage }}</h1>',
    
    controller: function ( $scope ) {
            
        $scope.indexPage = 'indexPage';
        
        console.log( this,arguments );
        
    }
    
})

.state('shop', {
    
    url: '/shop',
    
    template: '<h1>{{ shopPage }}</h1>',
    
    controller: function ( $scope ) {
        
        $scope.shopPage = 'shopPage';
        
        console.log( this,arguments );
        
    }
    
})

});    

uiRouter路由参数规则
路由规则:

  • 固定值:/key

  • 可捕获的参数: /:key

  • 限制字段类型: /{key:type} type: int,string

  • 捕获query: ?queryNum&queryNum2

$stateProvider.state('shop', {
    
    // url: '/shop/xixi/is/100?form=10&to=20'
    url: '/shop/:value/is/{pageNum:int}?form&to',
    
    template: '<h1>{{ shopPage }}</h1>',
    
    controller: function ( $scope, $stateParams ) {
        
        console.log( $stateParams );
        
        $scope.shopPage = 'shopPage';
        
    }
    
})    

$urlRouterProvider
when(); 将参数1的路由路径重定向到参数2路由路径
otherwise(); 匹配不存在的路由,跳转到定义过的路由.

// 配置 不存在路由    
$urlRouterProvider.when('', '/').otherwise('/error');

views 多视图
ui-router 可以渲染页面中的多个视图,通过为页面中ui-view指令添加名称,多个视图渲染需要在config() 配置。

<div>
    <div class="left" ui-view="leftView"></div>
    <div class="content" ui-view="contentView"></div>
    <div class="right" ui-view="rightView"></div>
</div>

app.config(function ( $stateProvider, $urlRouterProvider ) {

$stateProvider.state('home', {
    
    url: '/',
    
    views: {
        
        leftView: {
            
            template: '<h1>leftView</h1>'
            
        },
        
        rightView: {
            
            template: '<h1>rightView</h1>'
            
        },
        
        contentView: {
            
            template: '<h1>contentView {{ msg }}</h1>',
            
            controller: function ( $scope ) {
                
                $scope.msg = '中间模块'
                
            }
            
        }
        
    }
    
});

view 嵌套
在 ui-reouter 中视图是可以嵌套。
在state() 定义状态名称的时候添加命名空间。
路由需要有顺序,定义在父路由的后边。
注意:父视图需要添加动态视图ui-view
多视图不能与嵌套视图同时使用
匹配主页,定义路径不需要添加 '/shop', 直接 'shop';即可.

app.config(function ( $stateProvider, $urlRouterProvider ) {
    
    $stateProvider.state('home', {
        
        url: '/',
        
        template: '<div>index<div ui-view></div></div>'
        
    })
    .state('home.shop', {
        
        url: 'shop',
        
        template: '<h1>shopPage</h1>'
        
    });
    
    $urlRouterProvider.when('','/');
    
});

路由事件
添加在全局作用域$rootScope 下检测路径变化
事件名以state开头
参数1: 事件对象
参数2: 当前路由对象
参数3: 当前路由参数对象
参数4: 前一个路由对象
参数5: 前一个路由参数对象

app.run(function ( $rootScope ) {
    
    $rootScope.$on('$stateChangeSuccess', function ( ev, routeObj, routeParamsObj, preRouteObj, preRouteParamsObj ) {
        
        console.log( this,arguments );
        
    })
    
});

alogy
1.3k 声望121 粉丝

// Designer and Developer