这一篇我们来学习directive。
1.directive
angular有很多内置的指令,同时允许我们自定义指令。angular指令的作用大概可以概括成扩展HTML。其内置指令以ng开头,常见的有ng-app,ng-repeat, ng-model等.关于常见指令的使用和样例,我们给出一个参考资料,写的很好http://www.jb51.net/article/67944.htm 。我们这里就不再一一细数了。
2.link
我们的重点放在自定义指令的编写和使用上。我们先给出一个自定义指令的demo, 以期我们有一个整体的概念和感觉。
<!DOCTYPE html>
<html ng-app='app'>
<head>
<meta charset="UTF-8">
<title>MyDirective</title>
</head>
<body>
<script src="angular.js"></script>
<script src="angular.min.js"></script>
<script src="directiveCtrl.js"></script>
<h2>Hello</h2>
<hello></hello>
</body>
</html>
/**
*
*/
var app = angular.module('app',[]);
app.directive('hello', function(){
return{
restrict : 'E',
template : '<div>This is a template! </div>',
replace : true
};
});
下面是演示效果
我们看到<hello></hello>
代替了 <div> This is a template!</div>
起了作用。这段代码不难理解,下面我们再来看一个link的例子。
在刚才的js中添加部分代码,添加后如下:
/**
*
*/
var app = angular.module('app',[]);
app.directive('hello', function(){
return{
restrict : 'E',
template : '<div>This is a template! </div>',
replace : true
};
});
app.directive('linkdemo',function(){
return{
restrict : 'A',
replace : true,
scope : {},
template : '<button ng-click="sayhello()">click here !</button>',
link : function(scope, element, attrs){
scope.sayhello = function sayhello(){
console.log('hello world!');
}
}
};
});
html改造为:
<!DOCTYPE html>
<html ng-app='app'>
<head>
<meta charset="UTF-8">
<title>MyDirective</title>
</head>
<body>
<script src="angular.js"></script>
<script src="angular.min.js"></script>
<script src="directiveCtrl.js"></script>
<h2>Hello</h2>
<div linkdemo></div>
</body>
</html>
演示效果是:
这里我们可以看到,与第一个小Demo不一样的地方是我们这里的restrict使用了另外 一个参数‘A’,然后在引用的是偶,我们是像属性一样使用了它,是的,你没有猜错,‘A’ 即是 ‘Attribute’的缩写,即是属性的意思。下面会有详细的参数的分析。另外,我们在这里使用了link这个参数,可以看到,我们返回了一个函数来作为button的响应处理。下面我们就来看一下这几个参数。
(1)restrict
这个单词的中文翻译是限制、约束,映射到我们的编程中一般解释为限制符。在这里有以下几个取值
可以很清晰的看到,这里列出的四种方式,只不过是不同的写法而已,其产生的作用没什么本质区别。其中第四种方式,采用注释的方式来解析相应的指令,angular的这一做法很类似于spring中采用的注解。
(2)template
很简单,由字面意思来理解,就是模板的意思,是指定我们来替代的对象。那么,当我们需要替代的模板代码很多,这时候我们可以 采用templateUrl来指定一个路径,将冗长复杂的模板单独写到一个html中。
(3)link
link的中文意思是链接。这里我们就要来重温一下代码从书写到执行的过程了。写完代码以后,我们的代码要编译->链接->执行。这个可以对应到我们的angular中来,我们将在文章的最后明确他们各自的执行顺序。
当浏览器加载渲染一个页面的时候,本质上是读取html标示,然后建立dom节点,当dom数创建完了以后,广播一个事件给我们。
当我们使用script标签加载ng应用程序时候,ng监听上面的dom完成事件,然后再查找ng-app属性的元素,找到之后,ng开始处理dom,以这个元素为起点。举个例子,如果我们把ng-app加到html上,那么ng就会从html元素开始处理。如果加到body上,那么就会从body开始处理dom。如果单独使用了一个link, 那么系统默认等同于post-link处理。
link还有另外两种细分的方式,即pre和post,我们将在下面说明。
3.compile
return中的参数也可以有compile这一项。compile, 大家都很熟悉,是编译的意思。使用compile函数可以改变原始的dom, 在ng创建原始dom实例以及scope实例之前。
4.controller
是的,不同于$controller, 这个controller是指令内部的一个controller, controller会在prelink之前被初始化,并允许其他directive通过require来调用,这样一来,各个directive之间可以相互配合,灵活性更高。我们来看一个小的demo.
html部分
<!DOCTYPE html>
<html ng-app='app'>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="directiveCtr.css"></link>
<title>MyDirective</title>
</head>
<body ng-controller="SomeController">
<script src="angular.js"></script>
<script src="angular.min.js"></script>
<script src="directiveCtrl.js"></script>
<accordion>
<expander class="expander" ng-repeat='expander in expanders' expander-title='expander.title'>
{{expander.text}}
</expander>
</accordion>
</body>
</html>
js部分
/**
*
*/
var app = angular.module('app',[]);
app.directive('accordion', function(){
return{
restrict : 'EA',
replace : true,
transclude : true,
template : '<div ng-transclude></div>',
controller : function(){
var expanders = [];
this.gotOpened = function(selectedExpander){
angular.forEach(expanders, function(){
if(selectedExpander !=expander){
expander.showMe =false;
}
});
}
this.addExpander = function(expander){
expanders.push(expander);
}
}
}
});
app.directive('expander', function(){
return{
restrict : 'EA',
replace : true,
transclude : true,
require : '^?accordion',
scope :{
title : '=expanderTitle'
},
template : '<div>'
+'<div class="title" ng-click="toggle()">{{title}}</div> '
+'<div class="body" ng-show="showMe" ng-transclude></div>'
+'</div>',
link : function(scope, element, attrs, accordionController){
scope.showMe = false;
accordionController.addExpander(scope);
scope.toggle = function toggle(){
scope.showMe = !scope.showMe;
accordionController.getOpened(scope);
}
}
}
});
app.controller('SomeController', function($scope){
$scope.expanders = [{
title : 'Click me to expand',
text : 'this is the hidden content'
},{
title : 'click here',
text : 'there is a apple'
},{
title : 'money',
text : 'give you ¥1000,000,000,000,000'
}];
});
css部分
@CHARSET "UTF-8";
.expander{
border: 1px solid black;
width: 250px;
}
.expander>.title{
background-color: black;
color: white;
padding: .1em .3em;
cursor: pointer;
}
.expander>.body{
padding: .1em .3em;
}
效果展示:
总的来说,这段代码还是比较简单的,不做过多的解释。可能读者发现了一个transclude, 还发现了在一个指令中引用了另一个指令中的方法,我们将在下面一个transclude的部分,做一个讲解和分析。
5.prelink和postlink
按照我们之前提到的程序的执行过程,先是编译,然后链接,再然后执行。prelink和postlink也不难理解,是在链接前和链接后做的一个操作。我们还是来看一个例子。
html部分
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MyFile</title>
</head>
<body ng-app="app">
<script src="angular.js"></script>
<script src="angular.min.js"></script>
<script src="directiveCtrl.js"></script>
<level-one>
<level-two>
<level-three>
Hello
</level-three>
</level-two>
</level-one>
</body>
</html>
js部分
var app = angular.module('app',[]);
function createDirective(name){
return function(){
return{
restrict: 'E',
compile: function(tElem, tAttrs){
console.log(name+':compile');
return{
pre: function(scope, iElem, iAttrs){
console.log(name+':prelink');
},
post: function(scope, iElem, iAttrs){
console.log(name+':postlink');
}
}
}
}
}
}
app.directive('levelOne', createDirective('levelOne'));
app.directive('levelTwo', createDirective('levelTwo'));
app.directive('levelThree', createDirective('levelThree'));
效果演示
在这里可以看到compile和pre是顺序执行的,post是逆序执行的。引用别人的一张图来帮助大家更好地理解这个问题。
6.transclude
transclude的中文意思是嵌入。需要在模板中配合ng-transclude使用。 它是一个可选的参数。如果设置了,其值必须为true,它的默认值是false。
关于transclude的部分,笔者决定把它单独拿出来讲解,在下一篇我们单独学习它。
按照惯例,我们列出一些参考的文献和资料。
http://camnpr.com/javascript/1716.html
http://www.jb51.net/article/58229.htm
http://files.jb51.net/file_images/article/201412/2014126101701315.png?2014116101711
http://hudeyong926.iteye.com/blog/2073488
http://segmentfault.com/q/1010000000664866
http://damoqiongqiu.iteye.com/blog/1917971
http://www.jb51.net/article/60733.htm
http://www.jb51.net/article/67944.htm
http://blog.51yip.com/jsjquery/1607.html
http://lin-xi.diandian.com/post/2013-12-18/40060507046