紧接上篇博客“初探AngularJS

一、前言

在AngularJS中指令尤为重要且内容庞多,固单独提炼出来,梳理一番。如有错误,请不吝讲解。

好了,言归正传,让我们一起走进Angular指令的世界。

在上篇博客的前言部分提到,Angular的核心就是对HTML标签的增强。我们用到的诸如ng-app、ng-controller等等这些都是属于Angular指令,具体点,它们为Angular内置的指令。

Angular不仅提供了内置指令,它还允许我们自定义指令,不然Angular就太low咯。

这也是本篇博客的核心:如何自定义指令。

该篇博客原文地址:http://www.cnblogs.com/giggle/p/5746220.html

二、自定义指令

Angular为我们提供了.directive()这个方法,来定义指令。

如下:

正如上述代码所示,directive方法接受两个参数:name和factory_function。

  --name嘛,即为指令的名字,供我们调用时使用;

  --factory_function就是当我们调用指令时,指令的实际行为,并且factory_function通常返回一个对象,里面通过规定的设置项来定义指令。

那么自定义指令中,我们都可以操作哪些设置项呢?

如下:

var app = angular.module('myApp', []);
app.directive('myDirective', function(){ return {
restrict: 'EACM',//告诉AngularJS这个指令在DOM中以何种形式被声明,默认为A
priority: Number,//优先级参数(值为数值),数值越大,优先级越高,默认为0
terminal: Boolean,//true或者false,告诉AngularJS是(true)否(false)停止运行当前元素上比本指令优先级低的指令
template: String or Template Function,//模板
templateUrl: String,//模板URL
replace: Boolean,//值为true,代表模板会替换掉调用该指令的元素
scope: Boolean or Object,//指令作用域
transclude: Boolean,//true,结合ng-transclude,在该指令中嵌入内容
controller: String or function($scope, $element, $attrs, $transclude, otherInjectables){...},//指令控制器
controllerAs: String,//用来设置控制器的别名
require: String,//将控制器注入到其值所指定的指令中
link: function(scope, element, attrs){...},
compile: function(){}
};
});

代码稍长,请自行打开

针对如此众多的设置项,我们一同先挑几个常用且简单的设置项,感受感受吧。

--template & templateUrl--

template模板参数是可选的,其值可以是一段HTML文本,也可以是一个接受两个参数的函数。

注:如果template值为空,或者没有template设置项,那么不会覆盖嵌入在指令内部的元素,且当指令scope为false或者{…}时,内部元素的作用域共享外部父作用域;但,当指令scope为true时,内部元素的作用域就是继承自外部父作用域。

demo如下:

<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
</head>
<body ng-app="myModule">
outterDirective:<input type="text" ng-model="name"/><br>
<one>
innerDirective: <input type="text" ng-model="name"/>
</one>
<script src="angular.js"></script>
<script>
var myModule = angular.module('myModule', []);
myModule.directive('one', function(){
return {
scope: false,
restrict: 'E'
}
});
</script>
</body>
</html>

scope为false

效果图如下:

<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
</head>
<body ng-app="myModule">
outterDirective:<input type="text" ng-model="name"/><br>
<one>
innerDirective: <input type="text" ng-model="name"/>
</one>
<script src="angular.js"></script>
<script>
var myModule = angular.module('myModule', []);
myModule.directive('one', function(){
return {
scope: {},
restrict: 'E'
}
});
</script>
</body>
</html>

scope为{...}

scope:{...}效果同上

<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
</head>
<body ng-app="myModule">
outterDirective:<input type="text" ng-model="name"/><br>
<one>
innerDirective: <input type="text" ng-model="name"/>
</one>
<script src="angular.js"></script>
<script>
var myModule = angular.module('myModule', []);
myModule.directive('one', function(){
return {
scope: true,
restrict: 'E'
}
});
</script>
</body>
</html>

scope为true

scope为true,效果图如下:

假设,设置了template后,当我们调用指令后,它会呈现在页面中。下面我们就来具体看看。

1、当template值为一段HTML文本时,demo如下:

<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
</head>
<body ng-app="myApp">
<div my-directive></div>
<script src="angular.js"></script>
<script>
var app = angular.module('myApp', []);
app.directive('myDirective', function(){
return {
template: '<div>\
<h1>Hi everyone!</h1>\
</div>'
};
});
</script>
</body>
</html>

EntireCode

2、当template值为函数时,demo如下:

<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
</head>
<body ng-app="myApp">
<div my-directive title="Monkey"></div>
<script src="angular.js"></script>
<script>
var app = angular.module('myApp', []);
app.directive('myDirective', function(){
return {
/*
值为函数时,接受两个参数tElement, tAttrs:
tElement:使用此指令的元素
tAttrs:实例的属性,它是一个由元素上所有的属性组成的集合,即对象
*/
template: function(tElement, tAttrs){
var _html = '';
_html +='<div>' + 'Hi,'+tAttrs.title+'</div>';
return _html;
}
};
});
</script>
</body>
</html>

代码稍长,请自行打开

利用template可以在指令中自定义我们需要的模板,但是随着模板的体积(代码量)不断变大时,在指令中利用template就显得很糟糕,故而,使用templateUrl引用外部模板,是更好的选择。

--restrict--

restrict 是一个可选参数,它告诉AngularJS这个指令在DOM中以何种形式被调用。一共有四个选择且都为大写,不然没效果,默认为A(属性)。

A(属性):

<div my-directive></div>

E(元素):

<my-directive></my-directive>

C(类名):

<div class="my-directive"></div>

M(注释):

//以注释调用指令时,前后得有空格
<!-- directive:my-directive -->

这四个选项,可以单独使用,亦可混合使用。如:

restrict: ‘EA’就代表可以用元素或者属性调用指令

--replace--

replace是一个可选参数,值为Boolean类型,默认为false,代表模板会被当作子元素插入到调用此指令的元素内部。

如下:

<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
</head>
<body ng-app="myApp">
<div my-directive></div>
<script src="angular.js"></script>
<script>
var app = angular.module('myApp', []);
app.directive('myDirective', function(){
return {
replace: false,
template: '<div>Monkey</div>'
};
});
</script>
</body>
</html>

代码稍长,请自行打开

运行后,打开chrome调试器,结果如下:

--replace值为true,即模板会替换掉调用指令的元素,如下:

<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
</head>
<body ng-app="myApp">
<div my-directive></div>
<script src="angular.js"></script>
<script>
var app = angular.module('myApp', []);
app.directive('myDirective', function(){
return {
replace: true,
template: '<div>Monkey</div>'
};
});
</script>
</body>
</html>

代码稍长,请自行打开

运行后,打开chrome调试器,结果如下:

且,当值为true时,template会替代调用指令的元素,固template中的值,必须只包含一个根节点,不然会报错,如下:

<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
</head>
<body ng-app="myApp">
<div my-directive></div>
<script src="angular.js"></script>
<script>
var app = angular.module('myApp', []);
app.directive('myDirective', function(){
return {
replace: true,
template: '<div>Monkey</div><h1>Dorie</h1>'
};
});
</script>
</body>
</html>

代码稍长,请自行打开

运行后,打开chrome调试器,报错如下:

--transclude--

transclude是一个可选参数,表示是否允许在指令中,嵌入内容。值为Boolean,默认值为false代表不允许在指令中嵌入内容,如果手动设置为true后,要结合ng-transclude指令使用,不然和false效果一样。

下面我们一起来编写两个demo具体看看。

<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
</head>
<body ng-app="myApp">
<div my-directive>
<span>需要嵌入内容</span>
</div>
<script src="angular.js"></script>
<script>
var app = angular.module('myApp', []);
app.directive('myDirective', function(){
return {
transclude: false,
template: '<div>指令内容</div>'
};
});
</script>
</body>
</html>

transclude为false

运行代码,打开chrome调试器得下:

我们再来看看transclude:true的情况,将上述代码中的transclude的值改为true后,运行代码。

咦,我靠和上诉transclude:false的结果一样呢?

哦,对了,虽然我们将transclude的值设为true了,但是要结合ng-transclude指令嘛,不然,你让人家嵌入内容往哪插呢?

利用ng-transclude指令修改代码后,得下:

<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
</head>
<body ng-app="myApp">
<div my-directive>
<span>需要嵌入内容</span>
</div>
<script src="angular.js"></script>
<script>
var app = angular.module('myApp', []);
app.directive('myDirective', function(){
return {
transclude: true,
template: '<div>指令内容</div><div ng-transclude></div>'
};
});
</script>
</body>
</html>

代码稍长,请自行打开

运行代码,打开chrome调试器,得下:

注:利用ng-transclude指令标记的元素中,不管有没有内容,都将等同于无内容情况。

咦,利用transclude嵌入的内容,它们有自己的作用域吗?如果有,那么它们的作用域继承谁呢,指令or外部作用域?

答案:利用ng-transclude嵌入的内容的同时,会创建一个属于自己的作用域,即子作用域,且继承自外部作用域,并非指令。

--scope--

scope参数是可选的,它是直接影响指令的作用域。该参数可以被设置为不同的三个值,分别代表三种不同的作用域,下面我们就来一一说明。

1、scope: false

当scope的值为false时,也就是默认状态,代表指令共享父作用域,即没有自己的作用域。

如下:

<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
</head>
<body ng-app="myApp">
Parent:<input type="text" ng-model="name"/>
<directive-for-false></directive-for-false>
<script src="angular.js"></script>
<script>
var app = angular.module('myApp', []);
app.directive('directiveForFalse', function(){
return {
restrict: 'E',
scope: false,
template: '<div>Child: \
<input type="text" ng-model="name">\
</div>'
};
});
</script>
</body>
</html>

代码稍长,请自行打开

执行上述代码,效果图如下:

2、scope: true

当scope的值为true时,代表指令会创建自己的作用域,且继承自父作用域。

如下:

<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
</head>
<body ng-app="myApp">
Parent:<input type="text" ng-model="name"/>
<directive-for-true></directive-for-true>
<script src="angular.js"></script>
<script>
var app = angular.module('myApp', []);
app.directive('directiveForTrue', function(){
return {
restrict: 'E',
scope: true,
template: '<div>Child: \
<input type="text" ng-model="name">\
</div>'
};
});
</script>
</body>
</html>

代码稍长,请自行打开

执行上述代码,效果图如下:

3、scope: {…}

当scope的值为对象时,代表指令会切断与外界的联系,创建一个隔离的作用域,既不继承于父作用域,也不准内嵌的指令继承于自己。

一起写个demo,感受下“隔离作用域”不继承于父作用域,如下:

<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
</head>
<body ng-app="myApp">
Parent:<input type="text" ng-model="name"/>
<directive-for-obj></directive-for-obj>
<script src="angular.js"></script>
<script>
var app = angular.module('myApp', []);
app.directive('directiveForObj', function(){
return {
restrict: 'E',
scope: {},
template: '<div>Child: \
<input type="text" ng-model="name">\
</div>'
};
});
</script>
</body>
</html>

代码稍长,请自行打开

执行上述代码,效果图如下:

至于“不准内嵌的指令继承于自己”,参考上面的--transclude--

那当我们将scope设置为对象后,就成了一个无人问津的作用域,这样非常适合我们写插件之类的,但,怎么与外界交互呢?

这就涉及到所谓的绑定策略啦。

如下:

       scope的绑定策略

@

把当前属性作为字符串传递。你还可以绑定来自外层scope的值,在属性值中插入{{ }}即可。

=

与父scope中的属性进行双向绑定。

&

传递一个来自父scope的函数

下面,我们就针对上面的提示,逐个demo,感受体会下。

1、@策略

<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
</head>
<body ng-app="myApp"> <input type="text" ng-model="name"/> <directive-for-obj who="{{name}}" love="love Dorie"></directive-for-obj>
<script src="angular.js"></script>
<script>
var app = angular.module('myApp', []);
app.directive('directiveForObj', function(){
return {
restrict: 'E',
scope: {
who:'@',
what: '@love'
},
template: '<div><input type="text" ng-model="who"/> {{what}}</div>'
};
});
</script>
</body>
</html>

代码稍长,请自行打开

效果图,如下:

2、=策略

<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
</head>
<body ng-app="myApp"> <input type="text" ng-model="name"/> <directive-for-obj who="name" love="love Dorie"></directive-for-obj>
<script src="angular.js"></script>
<script>
var app = angular.module('myApp', []);
app.directive('directiveForObj', function(){
return {
restrict: 'E',
scope: {
who:'=',
what: '@love'
},
template: '<div><input type="text" ng-model="who"/> {{what}}</div>'
};
});
</script>
</body>
</html>

代码稍长,请自行打开

效果图,如下:

3、&策略

<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
</head>
<body ng-app="myApp"> <input type="text" ng-model="name"/> <directive-for-obj who="name" love="love Dorie" greet="sayWhat(wt, whr)"></directive-for-obj>
<script src="angular.js"></script>
<script>
var app = angular.module('myApp', []);
app.run(function($rootScope){
$rootScope.sayWhat = function(what, where){
alert('hello, '+what+' at '+where);
}
});
app.directive('directiveForObj', function(){
return {
restrict: 'E',
scope: {
who:'=',
what: '@love',
greet: '&'
},
template: '<div><input type="text" ng-model="who"/> {{what}}</div>\
<button ng-click="greet({wt: who, whr: who})">click</button>'
};
});
</script>
</body>
</html>

EntireCode

--controller--

controller参数可以是一个字符串或一个函数。

注:当设置为字符串时,会以该字符串的值为名字,到注册在应用中的控制器中查找,不管该指令的scope值是什么,如果应用中的控制器没有对应的控制器,则报错。

在控制器中,是的,控制器,包括了指令以及注册在应用中的,可以注入一些特殊的服务,供其使用,如下:

$scope

与指令元素相关联的当前作用域

$element

当前指令对应的元素

$attrs

当前元素的属性组成的对象,如:

<div id=”nav” name=”Monkey”></div>

属性对象为:

{

id:  ‘nav’,

name:  ‘Monkey’

}

并且,指令之间的控制器(controller)可以复用。

怎么复用呢?

这就需要结合下面将要介绍的require设置项啦。

--require--

require参数可以被设置为字符串或数组,字符串代表另外一个指令的名字。Require会将控制器注入到其值所指定的指令中,并作为当前指令的链接函数(link)的第四个参数。用法如下:

没有前缀

指令会在自身提供的控制器中进行查找,如果找不到任何控制器,则会抛出一个error

?

如果在当前的指令没有找到所需的控制器,则会将null传给link连接函数的第四个参数

^

如果在当前的指令没有找到所需的控制器,则会查找父元素的控制器

?^

综合前面?和^

AngularJS之指令的更多相关文章

  1. 带你走近AngularJS - 体验指令实例

    带你走近AngularJS系列: 带你走近AngularJS - 基本功能介绍 带你走近AngularJS - 体验指令实例 带你走近AngularJS - 创建自定义指令 ------------- ...

  2. AngularJs自定义指令详解(2) - template

    一些用于定义行为的指令,可能不需要使用template参数. 当指定template参数时,其值可以是一个字符串,表示一段HTML文本,也可以是一个函数,这函数接受两个参数:tElement和tAtt ...

  3. AngularJs自定义指令详解(1) - restrict

    下面所有例子都使用angular-1.3.16.下载地址:http://cdn.bootcss.com/angular.js/1.3.16/angular.min.js 既然AngularJs快要发布 ...

  4. angularJS自定义指令间的“沟通”

    由此例子我们可以看出,angularJS使用指令时link的执行顺序<html> <head> <meta charset="utf-8"/> ...

  5. AngularJS: 自定义指令与控制器数据交互

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  6. 学习AngularJs:Directive指令用法

    跟我学AngularJs:Directive指令用法解读(上) http://blog.csdn.net/evankaka/article/details/51232895 跟我学AngularJs: ...

  7. 《AngularJS》--指令的相互调用

    转载自http://blog.csdn.net/zhoukun1008/article/details/51296692 人们喜欢AngularJS,因为他很有特色,其中他的指令和双向数据绑定很吸引着 ...

  8. 学习AngularJs:Directive指令用法(完整版)

    这篇文章主要学习AngularJs:Directive指令用法,内容很全面,感兴趣的小伙伴们可以参考一下   本教程使用AngularJs版本:1.5.3 AngularJs GitHub: http ...

  9. 浅析AngularJS自定义指令之嵌入(transclude)

    AngularJS自定义指令的嵌入功能与vue的插槽十分类似,都可以实现一些自定义内容展现.在开始之前先简单介绍下自定义指令的transclude属性和AngularJS的内置指令ng-transcl ...

随机推荐

  1. 最近帮客户实施的基于SQL Server AlwaysOn跨机房切换项目

    最近帮客户实施的基于SQL Server AlwaysOn跨机房切换项目 最近一个来自重庆的客户找到走起君,客户的业务是做移动互联网支付,是微信支付收单渠道合作伙伴,数据库里存储的是支付流水和交易流水 ...

  2. 理解CSS视觉格式化

    前面的话   CSS视觉格式化这个词可能比较陌生,但说起盒模型可能就恍然大悟了.实际上,盒模型只是CSS视觉格式化的一部分.视觉格式化分为块级和行内两种处理方式.理解视觉格式化,可以确定得到的效果是应 ...

  3. “.Net 社区虚拟大会”(dotnetConf) 2016 Day 1 Keynote: Scott Hunter

    “.Net 社区虚拟大会”(dotnetConf) 2016 今天凌晨在Channel9 上召开,在Scott Hunter的30分钟的 Keynote上没有特别的亮点,所讲内容都是 微软“.Net社 ...

  4. LeetCode-5LongestPalindromicSubstring(C#)

    # 题目 5. Longest Palindromic Substring Given a string S, find the longest palindromic substring in S. ...

  5. macOS 我的装机

    最近多次配置 Mac 的开发环境,稍微记录一下 1 创建无付费信息的Apple ID 2 Xcode ​ gem 源更改 3 Alfred 4 微信 5 SourceTree 6 Sublime Te ...

  6. Bringing Whoops Back to Laravel 5

    You might be missing the "prettier" Whoops error handler from Laravel 4. If so, here's how ...

  7. MVC通过路由实现URL重写

    public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Ro ...

  8. 【夯实PHP基础】PHP常用类和函数总结

    本文地址 代码提纲: 1. 字符串处理类及函数 2. 数组处理类及函数 3 .web处理类及函数 将常用的PHP的类和函数总结到这里,主要是 自己用过的,比较有感觉. 1. [字符串处理] 1)[ut ...

  9. 【夯实Nginx基础】Nginx工作原理和优化、漏洞

    本文地址 原文地址 本文提纲: 1.  Nginx的模块与工作原理    2.  Nginx的进程模型    3 . NginxFastCGI运行原理        3.1 什么是 FastCGI   ...

  10. RunLoop 总结:RunLoop的应用场景(一)

    参考资料 好的书籍都是值得反复看的,那好的文章,好的资料也值得我们反复看.我们在不同的阶段来相同的文章或资料或书籍都能有不同的收获,那它就是好文章,好书籍,好资料.关于iOS 中的RunLoop资料非 ...