学习笔记-AngularJs(十)

前面一直在说自定义指令,但是却一直没有一次系统地去了解,现在需要我们一起来学习如何去使用自定义指令,去丰富html标签、属性,实现多元化、多功能的标签(或是属性)。辣么,啥是指令?要了解指令,首先需要了解AngularJs的HTML编译器,简单地说让浏览器认识你自定义指令或是Angular的指令集,将其行为运用到DOM上(视图),分两个过程编译和链接,编译阶段是遍历DOM并且收集所有的相关指令,生成一个链接函数;链接阶段是给通过编译阶段调用所说的链接函数来将模板与作用域链接起来,绑定一个作用域,生成一个动态的视图。作用域模型的任何改变都会反映到视图上,并且视图上的任何用户操作也都会反映到作用域模型。

那么说到底,由某个属性、元素名称、css类名出现而导致的行为,或者说是DOM的变化,能让你以一种声明式的方法来扩展HTML表示能力,这就是指令!

官网也写了一个比较详细的指令demo(具体属性分析如下):

var myModule = angular.module(...);

myModule.directive(‘directiveName‘, function factory(injectables) { //工厂函数里面injectables是何意呢?望知道的人告知
    var directiveDefinitionObject = {
        priority: 0, //优先级priority,Dom里面会有很多指令,定义优先级,可以使此指令优先执行
     terminal:false, //如果被设置为true,那么该指令就会在同一个DOM的指令集和中最后被执行
        template: ‘<div></div>‘, // or // function(tElement, tAttrs) { ... },
        // templateUrl: ‘directive.html‘, // or // function(tElement, tAttrs) { ... },  //template或templateUrl顾名思义就是模板文件,可以编写,也可以url,也可以是function(tElement,tAttrs){ return ... ;}

        replace: false, //是否替换现在的元素

        transclude: false, //重要属性之一,配合ng-transclude使用,为true时,可以将原元素的内容(html、其他指令)提取到带有指令ngTransclude的元素内,下面有例子说明!(注:指令的内部可以访问外部指令的作用域,并且模板也可以访问外部的作用域对象)

        restrict: ‘A‘, //以哪种形式声明指令行为的格式,有AECM,分别是属性<div my-directive="exp"> </div> 、元素*<my-directive></my-directive> 、 class*<div class="my-directive: exp;"></div> 、注释<!-- directive: my-directive exp -->

        templateNamespace: ‘html‘, //模板的命名空间,有‘html‘、‘svg‘等,默认为‘html‘

        scope: false, //是否创造一个新的作用域(针对指令)     /*scope是最难理解的一个属性*/

        controller: function($scope, $element, $attrs, $transclude, otherInjectables) {...
        }, //控制器的构造对象,预编译阶段执行,$scope当前作用域,$element当前元素,$attrs当前元素的属性集合,并且它是共享的,其他指令可以通过它的名字得到(参考依赖属性(通过require属性引入)。这就使得指令间可以互相交流来扩大自己的能力。当然也可以是控制        器名字(那么此控制器需要在应用声明好,这样便可以通过注入$attrs、$element操纵指令对应模板的dom),$transclude,用来操作嵌入作用域对应的dom,也就是被提取到ngTransclude的元素里面的dom了,下面有例子说明!

        controllerAs: ‘stringAlias‘, //定义控制器的别名

        require: ‘siblingDirectiveName‘, // or // [‘^parentDirectiveName‘, ‘?optionalDirectiveName‘, ‘?^optionalParent‘], // 请求将另一个控制器作为参数传入到当前链接函数。 这个请求需要传递被请求指令的控制器的名字。之前有例子关于表单自定义                        验证有使用到,学习笔记-AngularJs(八)

        compile: function compile(tElement, tAttrs, transclude) { //tElement指令所在的元素,tAttrs指令所在元素属性集合
            return {
                pre: function preLink(scope, iElement, iAttrs, controller) {...
                },
                post: function postLink(scope, iElement, iAttrs, controller) {...
                }
            }
            // or
            // return function postLink( ... ) { ... } //编译函数是用来处理需要修改模板DOM(执行于放到dom之前的dom操作)的情况的。因为大部分指令都不需要修改模板,所以这个函数也不常用。返回的是函数或是对象,返回函数时等效于link链接函数
        },
        // or
        // link: { //链接函数负责注册DOM事件和更新DOM。它是在模板被克隆之后执行的。 它也是大部分指令逻辑代码编写的地方。scope当前作用域,iElement当前元素,iAttrs当前元素的属性集合,controller就是上面require属性的值,于是就可以调用require进来的控制            器的属性方法,(包括之前讲的ngModel或是其他指令controller和controllerAs定义的有控制器名的控制器方法)
        // pre: function preLink(scope, iElement, iAttrs, controller) { ... }, // post: function postLink(scope, iElement, iAttrs, controller) { ... } // } // or // link: function postLink( ... ) { ... }
    };
    return directiveDefinitionObject;
});

compile和link选项是互斥的。如果同时设置了这两个选项,那么会把compile所返回的函数当作链接函数,而link选项本身则会被忽略。

编译函数负责对模板DOM进行转换。链接函数负责将作用域和DOM进行链接。

上面demo有些属性在实际操作上,都是取默认的属性,那么官网将其简化成了这个样子:

var myModule = angular.module(...);

myModule.directive(‘directiveName‘, function factory(injectables) { //此处需要注意,在视图引入指令时,采用的是骆峰命名法,所以调用时应该是directive-name
  var directiveDefinitionObject = {
    link: function postLink(scope, iElement, iAttrs) { ... }
  };
  return directiveDefinitionObject;
  // or
  // return function postLink(scope, iElement, iAttrs) { ... }
});

到这里还是需要编写些demo,才能起到学习的效果!

在之前的学习笔记-AngularJs(八)里面就有一个自定义表单验证的demo,情景是这样的,在input框里面不能写入“xiaobin”,主要是对ngModel中$setValidity(validationErrorKey, isValid);$setViewValue(value, trigger);在双向绑定中是如何实现scope->view、view->scope之间的那个验证和格式化的学习,没看过的话,可以去看一下,虽然理解得不透彻!下面贴一下主要代码:

var custom = angular.module(‘customControl‘, [‘ngSanitize‘]);

custom.directive("noxiaobin", function () {
return {
restrict: "A",
require: "?ngModel",
link: function (scope, element, attrs, ngModel) {
if (!ngModel) return;
ngModel.$parsers.push(function (v) { //传说中的验证器

if (v != "xiaobin") {
ngModel.$setValidity(‘noxiaobin‘, true); //通过获取从dom过来的值,然后进行验证,使用$setValidity(‘noxiaobin‘, true);改变noxiaobin的值,然后反馈会dom
return v;
} else {
ngModel.$setValidity(‘noxiaobin‘, false);
return undefined;
}

});
}
}
});

在这里,我们另外写一个比较综合的例子,dialog.html可到github下载(github地址:https://github.com/xiaobin5201314/AngularJS-Learning/tree/master/block-example/指令-13

<!doctype html>
<html ng-app=‘directiveModule‘>
    <head>
        <meta charset="utf8"/>
        <script src="../jquery.js"></script>
         <script src="../angular.js"></script>
         <script src="../bootstrap.min.js"></script>
         <link rel="stylesheet" href="../bootstrap.min.css">

        <script>
            var directive = angular.module(‘directiveModule‘, []);

            //这里是验证指令的内部可以访问外部指令的作用域,这样我们在dialog.html也可以查看到遍历出来的的arrs
            directive.controller("directiveControl",["$scope",function($scope){
                $scope.arrs=["我是内容一","我是内容二","我是内容三"];
                $scope.hide=false;
            }])

            //将任意可以被注入的ng服务注入到控制器中,便可以在指令中使用它了。控制器中也有一些特殊的服务可以被注入到指令当中,当然这是在应用上声明、也可以直接写在controller属性上
            directive.controller("directiveChildControl",[‘$scope‘,‘$attrs‘,‘$element‘,‘$transclude‘,function($scope,$attrs,$element,$transclude){
                    $element.css(‘border‘, ‘#fff‘);             //改变模板dom里面的结构
                    $transclude(function (clone) {              //这是操作嵌入的作用域里面的dom
                     var a = angular.element(‘<a>‘);
                     a.attr(‘href‘, ‘http://www.cnblogs.com/wuxiaobin‘);
                     a.text(‘我的博客原地址‘);
                     $element.find(‘.modal-body‘).append(a);
                 });
            }])

            directive.directive("dialog", function () {
                 return {
                     restrict: "AE",
                     replace: true,
                     transclude:true, //配合ng-transclude使用,为true时,可以将原元素的内容(html、其他指令)提取到带有指令ngTransclude的元素内
                     controller:‘directiveChildControl‘,
                     scope:{
                         title:"@" //模板也可以访问外部的作用域对象,dialog.html的{{title}}正是局部作用域访问父作用域的所产生的效果,这样可以很好实现我们的组件的设计思想,但对于@、=、&的写法有些不理解,望有更好的学习资料可以提供一下,当然搞懂了,也会更新上来
                     },
                     templateUrl: ‘dialog.html‘,
                     link: function(scope, element, attrs, ctrl) {
                        console.log(element.html());
                        element.find(‘.modal-title‘).css(‘color‘, ‘red‘);
                  }
             }
             });

        </script>

    </head>
    <body ng-controller="directiveControl">    

         <button class="btn btn-lg btn-primary " data-toggle="modal" data-target="#myModal">弹出模态框</button>
        <dialog title="我是传递过来的title">
            <span ng-repeat="arr in arrs" ng-hide="hide">
                {{$index}}-{{arr}} <br>
            </span>
            我的内容即将保存,被提取到<code>  span[ng-transclude] </code>上
        </dialog>

    </body>
</html>

效果图:

时间: 2024-11-29 11:01:47

学习笔记-AngularJs(十)的相关文章

angular学习笔记(二十四)-$http(2)-设置http请求头

1. angular默认的请求头: 其中,Accept 和 X-Requested-With是$http自带的默认配置 2. 修改默认请求头: (1) 全局修改(整个模块) 使用$httpProvider依赖 var myApp = angular.module('MyApp',[]); myApp.config(function($httpProvider){ console.log($httpProvider.defaults.headers.common) //修改/操作$httpProv

马哥学习笔记二十四——分布式复制快设备drbd

DRBD: 主从 primary: 可执行读.写操作 secondary: 文件系统不能挂载 DRBD: dual primay, 双主(基于集群文件系统的高可用集群) 磁盘调度器:合并读请求,合并写请求: Procotol:drbd数据同步协议 A: Async, 异步  数据发送到本机tcp/ip协议栈 B:semi sync, 半同步  数据发送到对方tcp/ip协议 C:sync, 同步  数据到达对方存储设备 DRBD Source: DRBD资源 资源名称:可以是除了空白字符外的任意

【Unity 3D】学习笔记二十八:unity工具类

unity为开发者提供了很多方便开发的工具,他们都是由系统封装的一些功能和方法.比如说:实现时间的time类,获取随机数的Random.Range( )方法等等. 时间类 time类,主要用来获取当前的系统时间. using UnityEngine; using System.Collections; public class Script_04_13 : MonoBehaviour { void OnGUI() { GUILayout.Label("当前游戏时间:" + Time.t

SaltStack 学习笔记 - 第十二篇: SaltStack Web 界面

SaltStack 有自身的用python开发的web界面halite,好处是基于python,可以跟salt的api无缝配合,确定就比较明显,需要个性化对web界面进行定制的会比较麻烦,如果喜欢体验该界面的可以参考下面的文章  http://rfyiamcool.blog.51cto.com/1030776/1275443/ 我是运用另一个python+php来进行web开发,具体需要的工具有在我的另一篇文章里面介绍过,这里再重新进行整个开发介绍 首先介绍php 跟python通信的工具 pp

Android学习笔记(十四)——在运行时添加碎片(附源码)

在运行时添加碎片 点击获取源码 将UI分割为多个可配置的部分是碎片的优势之一,但其真正强大之处在于可在运行时动态地把它们添加到活动中. 1.使用上一篇创建的Fragments项目,在main.xml文件中注释掉两个<fragment>元素: 2.在FragmentActivity.java中添加下面的代码: FragmentManager fragmentManager = getSupportFragmentManager();//向活动添加碎片 FragmentTransaction fr

Android学习笔记(十五)——碎片的生命周期(附源码)

碎片的生命周期 点击下载源码 与活动类似,碎片具有自己的生命周期.理解了碎片的生命周期后,我们可以在碎片被销毁时正确地保存其实例,在碎片被重建时将其还原到前一个状态. 1.使用上一篇的项目Fragments,在Fragment1.java文件中添加如下代码: package net.zenail.Fragments; import android.app.Activity; import android.os.Bundle; import android.support.v4.app.Fragm

angular学习笔记(二十八)-$http(6)-使用ngResource模块构建RESTful架构

ngResource模块是angular专门为RESTful架构而设计的一个模块,它提供了'$resource'模块,$resource模块是基于$http的一个封装.下面来看看它的详细用法 1.引入angular-resource.min.js文件 2.在模块中依赖ngResourece,在服务中注入$resource var HttpREST = angular.module('HttpREST',['ngResource']); HttpREST.factory('cardResource

MySQ学习笔记之十 NULL值处理

这是MySQL一大特殊之处. 概念上,NULL意味着"没有值"或"未知值",且它被看作有点与众不同的值.为了测试NULL,你不能使用算术比较运算符例如=.<或!=.为了说明它,试试下列查询: mysql> SELECT 1 = NULL, 1 != NULL, 1 < NULL, 1 > NULL; +----------+-----------+----------+----------+ | 1 = NULL | 1 != NULL |

Android学习笔记(十六)——碎片之间进行交互(附源码)

碎片之间进行交互 点击下载源码 很多时候,一个活动中包含一个或者多个碎片,它们彼此协作,向用户展示一个一致的UI.在这种情况下,碎片之间能进行通信并交换数据十分重要. 1.使用上一篇中创建的同一个项目,在fragment.xml中添加TextView的标识id: android:id="@+id/lblFragment1" 2.在fragment2.xml中添加一个Button,用于与fragment1进行交互: <Button android:id="@+id/btn