一、有感而发的一些话

  在学习ng之前有听前辈说过,angular上手比较难,初学者可能不太适应其语法以及思想。随着对ng探索的一步步深入,也确实感觉到了这一点,尤其是框架内部的某些执行机制,其复杂程度并非是我现在的功力能够理解的,只能是知其皮毛。我现在学习的途径是官方文档 + AngularJS在github上的中文粗译版(https://github.com/basestyle/angularjs-cn)+ 网上搜到的一些文章。鉴于本人资质平平以前也只用过jQuery,目前只能做到理解ng的API文档,相关特性的使用方式。故博客的主要内容也就是记载一些我的理解与应用,对ng框架内部的机制只做必要的了解,暂不深入探究。

  智商捉急,就到这里~

  接下来聊聊angular的指令机制。angular通过指令的方式实现了HTML的扩展,增强后的HTML就好比是究极进化后的暴龙兽,不仅长相焕然一新,同时也获得了很多强大的技能。更厉害的是,你还可以自定义指令,这就意味着HTML标签的范围可以扩展到无穷大,ng赋予了你造物主的能力。作为angular的精华之一,指令相关的知识也很多,本篇开始探索自定义指令的方方面面。为了不让我的篇幅再拉那么长,我识趣的在标题后面加了(上),你懂的。

二、指令的编译过程及命名方式

  在开始自定义指令之前,我们有必要了解一下指令在框架中的执行流程。这部分内容我没有自己研究,只是照搬了别人的说法:

  1. 浏览器得到 HTML 字符串内容,解析得到 DOM 结构。
  2. ng 引入,把 DOM 结构扔给 $compile 函数处理:

    ①   找出 DOM 结构中有变量占位符

    ②   匹配找出 DOM 中包含的所有指令引用

    ③   把指令关联到 DOM

    ④   关联到 DOM 的多个指令按权重排列

    ⑤   执行指令中的 compile 函数(改变 DOM 结构,返回 link 函数)

    ⑥   得到的所有 link 函数组成一个列表作为 $compile 函数的返回

  3. 执行 link 函数(连接模板的 scope)。

  这里注意区别一下$compile和compile,前者是ng内部的编译服务,后者是指令中的编译函数,两者发挥作用的范围不同。compile和link函数息息相关又有所区别,这个在后面会讲。了解执行流程对后面的理解会有帮助。

  在这里我小小的多嘴一下,有些人可能会问,angular不就是一个js框架吗,怎么还能跟编译扯上呢,又不是像C++那样的高级语言。其实此编译非彼编译,ng编译的工作是解析指令啦,绑定监听器啦,替换模板中的变量啦这些。因为工作方式很像高级语言编辑中的递归、堆栈过程,所以起名为编译,不要疑惑。

  指令的几种使用方式如下:

  作为标签:<my-dir></my-dir>

  作为属性:<span my-dir="exp"></span>

  作为注释:<!-- directive: my-dir exp -->

  作为类名:<span class="my-dir: exp;"></span>

  其实常用的就是作为标签和属性,下面两种用法目前还没见过,姑且留个印象。我们自定义的指令就是要支持这样的用法。

  关于自定义指令的命名,你可以随便怎么起名字都行,官方是推荐用[命名空间-指令名称]这样的方式,像ng-controller。不过你可千万不要用ng-前缀了,防止与系统自带的指令重名。另外一个需知道的地方,指令命名时用驼峰规则,使用时用-分割各单词。如:定义myDirective,使用时像这样:<my-directive>。

三、自定义指令的配置参数

  下面是定义一个标准指令的示例,可配置的参数包括以下部分:

myModule.directive('namespaceDirectiveName', function factory(injectables) {

        var directiveDefinitionObject = {

            restrict: string,//指令的使用方式,包括标签,属性,类,注释

            priority: number,//指令执行的优先级

            template: string,//指令使用的模板,用HTML字符串的形式表示

            templateUrl: string,//从指定的url地址加载模板

            replace: bool,//是否用模板替换当前元素,若为false,则append在当前元素上

            transclude: bool,//是否将当前元素的内容转移到模板中

            scope: bool or object,//指定指令的作用域

            controller: function controllerConstructor($scope, $element, $attrs, $transclude){...},//定义与其他指令进行交互的接口函数

            require: string,//指定需要依赖的其他指令

            link: function postLink(scope, iElement, iAttrs) {...},//以编程的方式操作DOM,包括添加监听器等

            compile: function compile(tElement, tAttrs, transclude){

                return: {

                    pre: function preLink(scope, iElement, iAttrs, controller){...},

                    post: function postLink(scope, iElement, iAttrs, controller){...}

                }

            }//编程的方式修改DOM模板的副本,可以返回链接函数

        };

        return directiveDefinitionObject;

});

看上去好复杂的样子啊~定义一个指令需要这么多步骤嘛?当然不是,你可以根据自己的需要来选择使用哪些参数。事实上priority和compile用的比较少,template和templateUrl又是互斥的,两者选其一即可。所以不必紧张,接下来分别学习一下这些参数,我将先从一个简单的例子开始。为了易于理解和我以后翻看的时候还能看明白,我尽量使用有语义的命名,而不是像test1,test2这样。

例子的代码如下:

var app = angular.module('MyApp', [], function(){console.log('here')});
app.directive('sayHello',function(){
return {
restrict : 'E',
template : '<div>hello</div>'
};
})

然后在页面中,我们就可以使用这个名为sayHello的指令了,它的作用就是输出一个hello单词。像这样使用:

<say-hello></say-hello>

这样页面就会显示出hello了,看一下生成的代码:

  

稍稍解释一下我们用到的两个参数,restirct用来指定指令的使用类型,其取值及含义如下:

取值

含义

使用示例

E

标签

<my-menu title=Products></my-menu>

A

属性

<div my-menu=Products></div>

C

<div class="my-menu":Products></div>

M

注释

<!--directive:my-menu Products-->

默认值是A。也可以使用这些值的组合,如EA,EC等等。我们这里指定为E,那么它就可以像标签一样使用了。如果指定为A,我们使用起来应该像这样:

<div say-hello></div>

从生成的代码中,你也看到了template的作用,它就是描述你的指令长什么样子,这部分内容将出现在页面中,即该指令所在的模板中,既然是模板中,template的内容中也可以使用ng-modle等其他指令,就像在模板中使用一样。

  在上面生成的代码中,我们看到了<div>hello</div>外面还包着一层<say-hello>标签,如果我们不想要这一层多余的东西了,replace就派上用场了,在配置中将replace赋值为true,将得到如下结构:

  

replace的作用正如其名,将指令标签替换为了temple中定义的内容。不写的话默认为false。

上面的template未免也太简单了,如果你的模板HTML较复杂,如自定义一个ui组件指令,难道要拼接老长的字符串?当然不需要,此时只需用templateUrl便可解决问题。你可以将指令的模板单独命名为一个html文件,然后在指令定义中使用templateUrl指定好文件的路径即可,如:

templateUrl : ‘helloTemplate.html’

系统会自动发一个http请求来获取到对应的模板内容。是不是很方便呢,你不用纠结于拼接字符串的烦恼了。如果你是一个追求完美的有考虑性能的工程师,可能会发问:那这样的话岂不是要牺牲一个http请求?

这也不用担心,因为ng的模板还可以用另外一种方式定义,那就是使用<script>标签。使用起来如下:

<script type="text/ng-template" id="helloTemplate.html">
<div>hello</div>
</script>

你可以把这段代码写在页面头部,这样就不必去请求它了。在实际项目中,你也可以将所有的模板内容集中在一个文件中,只加载一次,然后根据id来取用。

接下来我们来看另一个比较有用的配置:transclude,定义是否将当前元素的内容转移到模板中。看解释有点抽象,不过亲手试试就很清楚了,看下面的代码:

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

指定了transclude为true,并且template修改了一下,加了一个<b>标签,并在上面使用了ng-transclude指令,用来告诉指令把内容转移到的位置。那我们要转移的内容是什么呢?请看使用指令时的变化:

<say-hello>美女</say-hello>

内容是什么你也看到了哈~在运行的时候,美女将会被转移到<b>标签中,原来此配置的作用就是——乾坤大挪移!看效果:

  

这个还是很有用的,因为你定义的指令不可能老是那么简单,只有一个空标签。当你需要对指令中的内容进行处理时,此参数便大有可用。

四、结束

  看前面写的两篇,感觉篇幅太长了,可能会有人耐不住性子看完,故本篇先介绍几个比较简单的参数,先拿软的来捏一捏,更复杂的用法还在后头。我们将真正用一下自定义指令,起码也搞个像样的ui组件出来,这样才算是学会了。

  今天爬香山回来,累的够呛,时辰不早,收工睡觉~

走进AngularJs(三)自定义指令-----(上)的更多相关文章

  1. 走进AngularJs(五)自定义指令----(下)

    自定义指令学习有段时间了,学了些纸上谈兵的东西,还没有真正的写个指令出来呢...所以,随着学习的接近尾声,本篇除了介绍剩余的几个参数外,还将动手结合使用各参数,写个真正能用的指令出来玩玩. 我们在自定 ...

  2. 走进AngularJs(四)自定义指令----(中)

    上一篇简单介绍了自定义一个指令的几个简单参数,restrict.template.templateUrl.replace.transclude,这几个理解起来相对容易很多,因为它们只涉及到了表现,而没 ...

  3. 带你走近AngularJS - 创建自定义指令

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

  4. AngularJS笔记--自定义指令

    在前端开发中, 我们会遇到很多地方都会用到同一种类型的控件.AngularJS提供了自定义指令功能,我们可以在指令里面定义特定的html模板.提供给前台html调用. 一. 指令的简单定义.  下面定 ...

  5. angularJS中自定义指令

    学习了angularJS一周,但是大部分时间被自定义指令占用了.博主表示自学互联网好心塞的,发现问题的视觉很狭窄,这比解决问题要更难.这篇文章首先介绍了自定义,然后介绍了在使用自定义指令遇到的问题. ...

  6. angularJS 使用自定义指令输出模板

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script sr ...

  7. angularjs Directive自定义指令详解

    作用:需要用Directive有下面的情景: 1.使你的Html更具语义化,不需要深入研究代码和逻辑即可知道页面的大致逻辑. 2. 抽象一个自定义组件,在其他地方进行重用. 3.使用公共代码,减少重复 ...

  8. Angularjs进阶笔记(2)-自定义指令中的数据绑定

    有关自定义指令的scope参数,网上很多文章都在讲这3种绑定方式实现的效果是什么,但几乎没有人讲到底怎么使用,本篇希望聊聊到底怎么用这个话题. 一. 自定义指令 自定义指令,是Angularjs用来实 ...

  9. 带你走近AngularJS 之创建自定义指令

    带你走近AngularJS 之创建自定义指令 为什么使用AngularJS 指令? 使用过 AngularJS 的朋友应该最感兴趣的是它的指令.现今市场上的前端框架也只有AngularJS 拥有自定义 ...

随机推荐

  1. 123. Best Time to Buy and Sell Stock (三) leetcode解题笔记

    123. Best Time to Buy and Sell Stock III Say you have an array for which the ith element is the pric ...

  2. webpack+react配置

    $ npm install -g webpack $ npm install -g webpack-dev-server如果遇到类似 EACESS 错误,则需要用超级用户的模式运行 $ sudo np ...

  3. 结构化查询语言(SQL)数据类型

    简要描述一下结构化查询语言中的五种数据类型:字符型,文本型,数值型,逻辑型和日期型. 字符型 VARCHARVS CHAR VARCHAR型和CHAR型数据的这个差别是细微的,但是非常重要.他们都是用 ...

  4. 1282 - Leading and Trailing ---LightOj1282(快速幂 + 数学)

    http://lightoj.com/volume_showproblem.php?problem=1282 题目大意: 求n的k次方的前三位和后三位数然后输出 后三位是用快速幂做的,我刚开始还是不会 ...

  5. PHP使用XHProf进行性能分析

    1. 编译安装 wget http://pecl.php.net/get/xhprof-0.9.3.tgz tar zxvf xhprof-0.9.3.tgz cd xhprof-0.9.3/exte ...

  6. iOS 利用webView加载html代码,在代理中获取html页面的链接时出现的问题

    getDetailWebview.loadHTMLString(webViewData as String, baseURL:NSURL(string: "\(ProBaseWeb)&quo ...

  7. Win7 64位 VS2015环境使用qt-msvc2015-5.6.0

    QT下载 http://www.qt.io/download-open-source/#section-2 我用的是 qt-opensource-windows-x86-msvc2015-5.6.0. ...

  8. 服务器TIME_WAIT和CLOSE_WAIT详解和解决办法

    转载的服务器TIME_WAIT和CLOSE_WAIT详解和解决办法

  9. HibernateUtil

    package com.ssh.util; import org.hibernate.SessionFactory; import org.hibernate.boot.registry.Standa ...

  10. member template

    1.当且仅当类模板的参数相同时,你才能对类实体对象相互赋值,即将一个实体对象整体赋值给另外一个实体对象.不能将一种类型的实体对象赋值给另外一种实体对象.如: Stack<int> intS ...