Angularjs学习笔记(五)指令

一、指令基础
当浏览器加载一个包含AngularJS应用的HTML时,我们只需要用内置指令ng-app启动AngularJS应用,并标记出应用的根节点,这个指令需要以属性的形式来使用,因此可以将它写到任何位置,但是写到<html>的开始标签上是最常规的做法:
1.指令的使用方式

<html ng-app="myApp">
<!-- 应用的$rootScope -->
</html>

任何在这个根元素内部的指令只要能够访问作用域,就可以访问$rootScope。
2.自定义指令
通过AngularJS模块API中的.directive()方法,我们可以通过传入一个字符串和一个函数来注册一个新指令。其中字符串是这个指令的名字,指令名应该是驼峰命名风格的,函数应该返回
一个对象。directive()方法返回的对象中包含了用来定义和配置指令所需的方法和属性。

angular.module('myApp',[])
.directive('myDirective', function() {
return {
restrict: 'E',
template: '<a href="http://google.com">
Click me to go to Google</a>' //为了尽快掌握简单的属性定义,我们只用了restrict和template两个设置项来定义指令
};
});

为了让AngularJS能够调用我们的指令,需要修改指令定义中的restrict设置。这个设置告、诉AngularJS在编译HTML时用哪种声明格式来匹配指令定义。我们可以指定一个或多个格式。可以以元素(E) 、属性(A) 、类(C)或注释(M)的格式来调用指令,建议用属性A(在已有的标签上添加功能)和元素(使用模板的时候)的方式来调用。
这里写图片描述

AngularJS在页面加载以及调用指令定义后生成的代码, AngularJS把生成后的代码提供给Chrome进行渲染。默认情况下, AngularJS将模板生成的HTML代码嵌套在自定义标签<my-directive>内部
这里写图片描述
向指令定义中添加一些新的设置:我们可以将自定义标签从生成的DOM中完全移除掉,
并只留下由模版生成的链接。将replace设置为true就可以实现这个效果:

angular.module('myApp', [])
.directive('myDirective', function() {
return {
restrict: 'E',
replace: true,
template: '<a href="http://google.com">Click me to go to Google</a>'
};
});

这里写图片描述
当AngularJS启动应用时,它会把第一个参数当作一个字符串,并以此字符串为名来注册第二个参数返回的对象。 AngularJS编译器会解析主HTML的DOM中的元素、属性、注释和CSS类名中使用了这个名字的地方,并在这些地方引用对应的指令。当它找到某个已知的指令时,就会在页面中插入指令所对应的DOM元素。

template参数是可选的,必须被设置为以下两种形式之一:
 一段HTML文本;
 一个可以接受两个参数的函数,参数为tElement和tAttrs,并返回一个代表模板的字符串。
如果模板字符串中含有多个DOM元素,或者只由一个单独的文本节点构成,那它必须被包含在一个父元素内。换句话说,必须存在一个根DOM元素:

template: '\
<div> <-- single root element -->\
<a href="http://google.com">Click me</a>\
<h1>When using two elements, wrap them in a parent element</h1>\
</div>\

另外,注意每一行末尾的反斜线,这样AngularJS才能正确解析多行字符串。

templateUrl是可选的参数,可以是以下类型:
 一个代表外部HTML文件路径的字符串;
 一个可以接受两个参数的函数,参数为tElement和tAttrs,并返回一个外部HTML文件路径的字符串。
默认情况下,调用指令时会在后台通过Ajax来请求HTML模板文件。有两件事情需要知道。
 在本地开发时,需要在后台运行一个本地服务器,用以从文件系统加载HTML模板,否则会导致Cross Origin Request Script(CORS)错误。
 模板加载是异步的,意味着编译和链接要暂停,等待模板加载完成。

我们自定义指令是为了复用,肯定会用在不同的controller里面。为了在不同的控制器里面使用自定义指令,需要为指令增加配置项attr,指令怎么根据配置项调用不同控制器的方法?见下第5条:link
3.向指令中传递数据
注意,我们在模板中硬编码了URL和链接文本:

template:'<a href="http://google.com"> Click me to go to Google</a>'

我们的目标是关注指令的公共接口,就像其他任何编程语言一样。实际上,应该将上面的模板转换成可以接受两个变量的形式:一个变量是URL,另一个是链接文本:
template: '<a href="{{ myUrl }}">{{ myLinkText }}</a>'
在主HTML文档中,可以给指令添加myUrl和myLinkText两个属性,这两个参数会成为指令内部作用域的属性:

<div my-directive my-url="http://google.com"
my-link-text="Click me to go to Google">
</div>

有好几种途径可以设置指令内部作用域中属性的值。最简单的方法就是使用由所属控制器提供的已经存在的作用域。如果控制器被移除,或者在控制器的作用域中也定义了一个叫myUrl的属性,AngularJS 允许通过创建新的子作用域或者隔离作用域来解决这个常见问题。

<div my-directive my-url="http://google.com"
my-link-text="Click me to go to Google"></div>
angular.module('myApp', [])
.directive('myDirective', function() {
    return {
        restrict: 'A',
        replace: true,

        scope: {
            myUrl: '@', //绑定策略
            myLinkText: '@' //绑定策略
        },

        template: '<a href="{{myUrl}}">' +'{{myLinkText}}</a>'
    };
});

4.缓存
在模板第一次被引用时,它会被载入到模板缓存中以便快速的检索。angular直接通过 $templateCache 服务
这里写图片描述
5.link 方法:
回顾:
directive中的几个属性:
restrict
E: 表示该directive仅能以element方式使用,即:<my-dialog></my-dialog>
A: 表示该directive仅能以attribute方式使用,即:<div my-dialog></div>
EA: 表示该directive既能以element方式使用,也能以attribute方式使用
transclude
directive可能接受页面上的其他html内容时才会用到,建议先去掉该参数。有些高阶了。
scope
写上该属性时,就表示这个directive不会从它的controller里继承$scope对象,而是会重新创建一个。
templateUrl
你的directive里的html内容
link
可以简单理解为,当directive被angular 编译后,执行该方法,是用来处理指令内部事务的,包括:给元素绑定事件/数据之类的。

compile在编译前执行,负责把template(包括transclude所引用的)变成一个完整的DOM结构。 link在编译后执行,
负责根据controller和scope里的东东,给compile得到的DOM注册事件、关联数据,或者repeat之。

link里面有三个参数:
第一个参数scope基本上就是上面写的那个scope。
element简单说就是$(‘my-dialog’)
attrs是个map,内容是你这个directive上的所有属性,
require 之后,link就会多一个参数(第四个参数,scope,element,attrs,superCon
这里写图片描述
当有两种加载方式时,可以给自定义指令增加属性:
这里写图片描述
指令内部怎么获取到哪种加载方式呢?attr!直接写属性小写名,不要加括号
这里写图片描述

那什么时候把逻辑写在controller里,什么时候写在link里呢?
如果想让方法暴露出结果,在外部被调用,则写在controller里
link是处理指令内部的事物的,比如给元素绑定事件、数据
6.指令间的交互
假设现在我们要编写两个指令,两个指令中的link链接函数中(link函数后面会讲)存在有很多重合的方法,
这时候我们就可以将这些重复的方法写在第三个指令的controller中(上面也讲到controller经常用来提供指令间的复用行为)
然后在这两个指令中,require这个拥有controller字段的的指令(第三个指令通过require以及link第四个参数——这里是supermanCtrl):

var myModule = angular.module("MyModule", []);
myModule.directive("superman", function() {
    return {
        scope: {},  //创建独立作用域
        restrict: 'AE',
        controller: function($scope) {
            $scope.abilities = [];
            this.addStrength = function() {
                $scope.abilities.push("strength");
            };
            this.addSpeed = function() {
                $scope.abilities.push("speed");
            };
            this.addLight = function() {
                $scope.abilities.push("light");
            };
        },
        link: function(scope, element, attrs) {
            element.addClass('btn btn-primary');
            element.bind("mouseenter", function() {
                console.log(scope.abilities);
            });
        }
    }
});
myModule.directive("strength", function() {
    return {
        require: '^superman',//把supermanCtrl自动注入到指令中,就可以调用superman控制器中的方法了
        link: function(scope, element, attrs, supermanCtrl) {   
            supermanCtrl.addStrength();
        }
    }
});
myModule.directive("speed", function() {
    return {
        require: '^superman',
        link: function(scope, element, attrs, supermanCtrl) {
            supermanCtrl.addSpeed();
        }
    }
});
myModule.directive("light", function() {
    return {
        require: '^superman',
        link: function(scope, element, attrs, supermanCtrl) {
            supermanCtrl.addLight();
        }
    }
});

页面代码:

<div class="row">
        <div class="col-md-3">
            <superman strength>动感超人---力量</superman>
        </div>
    </div>
    <div class="row">
        <div class="col-md-3">
            <superman strength speed>动感超人2---力量+敏捷</superman>
        </div>
    </div>
    <div class="row">
        <div class="col-md-3">
            <superman strength speed light>动感超人3---力量+敏捷+发光</superman>
        </div>
    </div>

7、创建独立scope
为了使指令相互独立使用,我们应该在return里面创建独立scope:

myModule.directive("superman", function() {
    return {
        scope: {},  //创建独立作用域
        restrict: 'AE',
        controller: function($scope) {
        }
    }
});

angularjs scope的绑定策略:见另一篇博文

二、内置指令
这里写图片描述
这里只列出几个常用的:
(1)ng-app 定义应用程序的根元素。
声明了ng-app的元素会成为$rootScope的起点,而$rootScope是作用域链的根,通常声明在<html>
(2)ng-model:将表单控件和当前作用域的属性进行绑定,需要注意绑定的scope的范围(父scope与子scope)

<div ng-app="myApp" ng-controller="myCtrl">
    <input ng-model="name"> //input加上ng-model指令后,框架会负责input和name变量的自动同步。
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
    $scope.name = "John Doe";
});
</script>

我们应该始终用ngModel来绑定$scope上一个数据模型内的属性,而不是$scope上的属性,这可以避免在作用域或后代作用域中发生属性覆盖。例如:

<input type="text"
ng-model="modelName.someProperty" />

(3)ng-init:该指令被调用时会初始化内部作用域。
这个指令一般会出现在比较小的应用中,比如demo什么的

<div ng-init="job='fighter'">
    I'm a/an {{job}}
</div>

(4)ng-controller :用来定义一个控制器对象
内置指令ng-controller的作用是为嵌套在其中的指令创建一个子作用域,避免将所有操作和模型都定义在$rootScope上。用这个指令可以在一个DOM元素上放置控制器。

<div ng-app="myApp" ng-controller="myCtrl">
Full Name: {{firstName + " " + lastName}}
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
    $scope.firstName = "John";
    $scope.lastName = "Doe";
});
</script>

(5)ng-form :用来定义一个from,通常是用来验证参数
场景稍微复杂一点,比如一个父表单中有多个子表单,子表单中有3个验证通过时父表单便可以提交。但是,<form>是不可以嵌套的。考虑到这种场景,我们便使用ng-form指令来解决这一问题。
详细说明ng-form:见后

<form name="mainForm" novalidate>
    <div ng-form="form1">
        姓名:<input type="text" ng-required="true" ng-model="name"/><br>
        证件号码:<input type="number" ng-minLength="15" ng-maxLength="18" ng-required="true" ng-model="idnum"/>
    </div>
    <br>
    <div ng-form="form2">
        监护人姓名:<input type="text" ng-required="true" ng-model="gname"/><br>
        监护人证件号码:<input type="number" ng-minLength="15" ng-maxLength="18" ng-required="true" ng-model="gidnum"/>
    </div>
    <button ng-disabled="form1.$invalid && form2.$invalid">submit all</button>
</form>

ng-valid (有效的).
ng-invalid (无效的).

<input type="submit" ng-disabled="mainForm.$invalid" /> //也就是表单的状态为$invalid时禁用提交按钮。

ng-pristine (原始,简介).
ng-dirty (脏的).
ng-submitted (提交的)
下面四个是用到HTML的布尔属性:
(6)ng-disabled :禁用表单输入字段。——布尔
使用ng-disabled可以把disabled属性绑定到以下表单输入字段上:
<input> (text、 checkbox、 radio、 number、 url, email、 submit);
<textarea>
<select>
<button>
在下面的例子中按钮会一直禁用,直到用户在文本字段中输入内容:

<input type="text" ng-model="someProperty" placeholder="TypetoEnable">
<button ng-model="button" ng-disabled="!someProperty">AButton</button>

(7)ng-readonly :通过表达式返回值true/false将表单输入字段设为只读。——布尔
比如:3秒后变成只读.

<input type="text" ng-readonly="stopTheWorld" value="stop the world after 3s"/>

angular.module('myApp', [])
.run(function($rootScope,$timeout){
    $rootScope.stopTheWorld=false;
    $timeout(function(){
        $rootScope.stopTheWorld = true;
    },3000)
})

(8) ng-checked : 这个是给<input type="checkbox" />用的
——布尔

<input type="checkbox" ng-checked="someProperty" ng-init="someProperty = true" ng-model="someProperty">

(9) ng-selected : 给<select>里面的<option>用的
——布尔

<label>
    <input type="checkbox" ng-model="isFullStack">
    I'm Full Stack Engineer
</label>
<select>
    <option>Front-End</option>
    <option>Back-End</option>
    <option ng-selected="isFullStack">Full Stack !!!</option>
</select>

(10)ng-show/ng-hide/ng-if
ng-show 指令在表达式为 true 时显示指定的 HTML 元素,否则隐藏指定的 HTML 元素。
根据表达式显示/隐藏**HTML元素,注意是隐藏,不是从DOM移除(**ng-if才是移除),对于大对象的DOM,可以用它,但如果是小对象的DOM,建议使用ng-if

<div ng-show="1+1 == 2">
    1+1=2
</div>

如果ng-if中的表达式为false,则对应的元素整个会从DOM中移除

<body ng-app="">
保留 HTML: <input type="checkbox" ng-model="myVar" ng-init="myVar = true">
<div ng-if="myVar">
<h1>Welcome</h1>
<p>Welcome to my home.</p>
<hr>
</div>
<p>当复选框取消选中时 DIV 元素将移除。</p>
<p>当重新选中复选框,DIV 元素会重新显示。</p>
</body>

(11)ng-change :用来设置input/select等内容发生变化时的事件,这个指令要和ngModel联合起来使用。

<input type="text" ng-model="calc.arg"  ng-change="calc.result = calc.arg*2" />
    <code>{{ calc.result }}</code>

(12) ng-bind : ng-bind的行为和{{}}差不多,只是我们可以用这个指令来避免未渲染导致的闪烁。
(13) ng-repeat : 遍历集合(数组),给每个元素生成模板实例,每个实例的作用域中可以用一些特殊属性

<ul class="list-group">
      <li ng-repeat="item in tasks track by $index" class="list-group-item" >{{item}}
</ul>

(14) 鼠标、键盘事件:
ng-click :点击事件
ng-keyup :按键松开时执行的代码
ng-keydown : 按下按键时执行的代码,目前的测试是ngKeypress针对系统按键是无效的,而ngKeydown可以
ng-keypress : 按下按键时执行的代码
ng-mousedown()、ng-mouseenter、ng-mouseleave、ng-mousemove、ng-mouseover、ng-mouseup
(鼠标点击执行的顺序:Mousedown、 Mouseup、 Click。
不论鼠标指针穿过被选元素或其子元素,都会触发 mouseover 事件。对应mouseout。只有在鼠标指针穿过被选元素时,才会触发 mouseenter 事件。对应mouseleave这样的话,mouseenter子元素不会反复触发事件,否则在IE中经常有闪烁情况发生。)
(15)ng-class : 用作用域中的对象动态改变类样式
(16)ng-href、ng-src : ng-href 指令确保了链接是正常的,即使在 AngularJS 执行代码前点击链接。ng-src 指令确保的 AngularJS 代码执行前不显示图片。即表达式生效前不要加载该资源。如果在 href 的值中有 AngularJS 代码,则需要使用 ng-href 而不是 href。

<a ng-href="string"></a>

(17)ng-include:使用ng-include可以加载、编译并包含外部HTML片段到当前的应用中。
要记住,使用ng-include时AngularJS会自动创建一个子作用域。如果你想使用某个特定的作用域,例如ControllerA的作用域,必须在同一个DOM元素上添加ng-controller =”ControllerA”指令,这样当模板加载完成后,不会像往常一样从外部作用域继承并创建一个新的子作用域。

<div ng-include="/myTemplateName.html"
ng-controller="MyController"
ng-init="name = 'World'">
Hello {{ name }}
</div>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值