天天看点

Angular.js学习笔记(四)

这一篇我们来学习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
    };
});
           

下面是演示效果

Angular.js学习笔记(四)

我们看到

<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>
           

演示效果是:

Angular.js学习笔记(四)

这里我们可以看到,与第一个小Demo不一样的地方是我们这里的restrict使用了另外 一个参数‘A’,然后在引用的是偶,我们是像属性一样使用了它,是的,你没有猜错,‘A’ 即是 ‘Attribute’的缩写,即是属性的意思。下面会有详细的参数的分析。另外,我们在这里使用了link这个参数,可以看到,我们返回了一个函数来作为button的响应处理。下面我们就来看一下这几个参数。

(1)restrict

这个单词的中文翻译是限制、约束,映射到我们的编程中一般解释为限制符。在这里有以下几个取值

Angular.js学习笔记(四)

可以很清晰的看到,这里列出的四种方式,只不过是不同的写法而已,其产生的作用没什么本质区别。其中第四种方式,采用注释的方式来解析相应的指令,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: px solid black;
    width: px;
}
.expander>.title{
    background-color: black;
    color: white;
    padding: .em .em;
    cursor: pointer;
}
.expander>.body{
    padding: .em .em;
}
           

效果展示:

Angular.js学习笔记(四)

总的来说,这段代码还是比较简单的,不做过多的解释。可能读者发现了一个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'));
           

效果演示

Angular.js学习笔记(四)

在这里可以看到compile和pre是顺序执行的,post是逆序执行的。引用别人的一张图来帮助大家更好地理解这个问题。

Angular.js学习笔记(四)

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

继续阅读