AngularJS学习笔记(2) --- 指令参数和scope绑定策略-程序员宅基地

引言

指令(Directive)可以说是 AngularJS 的核心,而其开发也是比较困难的,本文主要介绍指令的一些参数和scope的绑定策略。

参数

从 AngularJS 的官方文档中看到指令的参数如下:

{
    priority: 0,
    template: '<div></div>', // or // function(tElement, tAttrs) { ... },
    // or
    // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
    transclude: false,
    restrict: 'A',
    scope: false,
    controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
    controllerAs: 'stringAlias',
    require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
    compile: function compile(tElement, tAttrs, transclude) {
      return {
        pre: function preLink(scope, iElement, iAttrs, controller) { ... },
        post: function postLink(scope, iElement, iAttrs, controller) { ... }
      }
      // or
      // return function postLink( ... ) { ... }
    },
    // or
    // link: {
    //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
    //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
    // }
    // or
    // link: function postLink( ... ) { ... }
}

下面详细讲解每个参数。

priority(Number)

指令执行的优先级,用于多个指令同时作用于同一个元素时。例如:

<select>
    <option ng-repeat="i in [1, 2]" ng-bind="i"></option>
</select>

上面的例子中,ng-repeat 指令和 ng-bind 指令同时作用于 option 元素,由于 ng-repeat 的 priority 为1000,ng-bind 的 priority 为0,因此先执行 ng-repeat,然后变量 i 的值才能用于 ng-bind 中。

template(String or Function)

HTML模板内容,用于下列情况之一:

  • 替换元素的内容(默认情况)。

  • 替换元素本身(如果 replace 选项为 true)。

  • 将元素的内容包裹起来(如果 transclude 选项为 true,后面会细说)。

值可以是:

  • 一个 HTML 字符串。例如:<div>my name is { {name}}</div>

  • 一个函数,接收两个参数 tElement(元素本身) 和 tAttrs(元素的属性集合),返回 HTML 字符串。

templateUrl(String or Function)

templateUrl 和 template 作用相同,但模板内容是从 $templateCache 服务或远程 url 加载。

值可以是:

  • 一个字符串,AngularJS 会先从 $templateCache 中查找是否缓存了对应值,如果没有则尝试 ajax 加载。例如:在页面中有如下 script:
    HTML <script type="text/ng-template" id="Hello.html"> <p>Hello</p> </script>
    AngularJS 会将 type="text/ng-template"script 标签中的内容以 id 值为 key 缓存到 $templateCache 服务中,此时可以设置 templateUrl: 'Hello.html'

  • 一个函数,接收两个参数 tElement(元素本身) 和 tAttrs(元素的属性集合),返回 url 地址。

transclude(Boolean)

官方文档的解释为:编译元素的内容,使其在指令内部可用。该选项一般和 ng-transclude 指令一起使用。

如果 transclude 设置为 true,则元素的内容会被放到模板中设置了 ng-transclude 指令的元素中。例如:

app.directive('testTransclude', [
    function () {
        return {
            restrict: 'E',
            transclude: true,
            template:
                '<div>\
                    <p>指令内部段落</p>\
                    <div ng-transclude></div>\
                </div>'
        };
    }
]);
<test-transclude>
    <p>该段落会被放到指令内部</p>
</test-transclude>

上面生成后的 DOM 结构为:

transclude执行结果

restrict(String)

指令的使用形式。

值可以为:

  • 'E' - 指令作为元素使用
  • 'A' - 指令作为属性使用
  • 'C' - 指令作为类名使用
  • 'M' - 指令作为注释使用(不常用)

可以是以上值的组合,如 restrict: 'EA' 表示指令既可以作为属性使用,也可以作为元素使用。

scope(Boolean or Object)

关于 scope 选项将会在后面的指令 scope 中细说。

controller(Function)

一般情况下不需要使用指令的 controller,只要使用 link 就够了,后面会细说 link 函数。

controller 的场景是该指令(a)会被其他指令(b)require 的时候,在 b 的指令里可以传入 a 的这个 controller,目的是为了指令间的复用和交流。而 link 只能在指令内部中定义行为,无法做到这样。

controllerAs(String)

为控制器指定别名,这样可以在需要控制器的地方使用该名字进行注入。

require(String or Array)

表示指令依赖于一个或多个指令,并注入所依赖指令的控制器到 link 函数的第四个参数中。如果所依赖的指令不存在,或所依赖指令的控制器不存在则会报错。

依赖名称前缀可以为:

  • (没有前缀) - 在当前元素中查找依赖指令的控制器,如果不存在则报错。
  • ? - 在当前元素中查找依赖指令的控制器,如果不存在传 nulllink 中。
  • ^ - 在当前元素及父元素中查找依赖指令的控制器,如果不存在则报错。
  • ?^ - 在当前元素及父元素中查找依赖指令的控制器,如果不存在传 nulllink 中。

例子:

app.directive('validate', [
    function () {
        return {
            restrict: 'A',
            require: 'ngModel',
            link: function (scope, ele, attrs, ngModelCtrl) {
                // 监听值变化
                ngModelCtrl.$viewChangeListeners.push(function () {
                    scope.validateResult = ngModelCtrl.$viewValue === 'Heron';
                });
            }
        };
    }
]);

app.controller('myCtrl', [
    '$scope',
    '$cookieStore',
    function ($scope, $cookieStore) {
        $scope.name = 'Heron';

        $scope.sayHi = function (name, age) {
            alert('Hello ' + name + ', your age is ' + age);
        }
    }
]);
<div ng-controller="myCtrl">
    <input type="text" ng-model="name" validate>
    <p>
        validate 结果:{
     {validateResult}}
    </p>
</div>

运行结果如图:

require运行结果

compile(Function)link(Function)

创建的创建过程可以分为编译(compile)阶段和链接(link)阶段,因此两者放一起讲。

两者区别在于:

  • compile 函数的作用是对指令的模板进行转换。

  • link 函数的作用是在视图和模型之间建立关联,包括注册事件监听函数和更新 DOM 操作。

  • scope 在链接阶段才会被绑定到元素上,因此 compile 函数中没有入参 scope

  • 对于同一个指令的多个示例,compile 函数只会执行一次,而 link 函数在每个实例中都会执行。

  • 如果自定义了 compile 函数,则自定义的 link 函数 无效,而是使用 compile 函数 返回的 link 函数。

指令 scope

scope 选项有三种值:

  • false - 使用父 scope。改变父 scope 会影响指令 scope,反之亦然。

  • true - 继承父 scope,并创建自己的 scope。改变父 scope 会影响指令 scope,而改变指令 scope 不会影响父 scope

  • {} - 不继承父 scope,创建独立的 scope。如果不使用双向绑定策略(后面会讲),改变父 scope 不会影响指令 scope,反之亦然。

例子:

app.controller('myCtrl', [
    '$scope',
    '$cookieStore',
    function ($scope, $cookieStore) {
        $scope.scopeFalse = 'Heron';
        $scope.scopeTrue = 'Heron';
        $scope.scopeObject = 'Heron';
    }
]);
 
app.directive('directiveFalse', [
    function () {
        return {
            restrict: 'EA',
            scope: false,
            template: 
                '<div>\
                    <p>\
                        <span>指令 scope: </span>\
                        <input type="text" ng-model="scopeFalse">\
                    </p>\
                </div>'
        };
    }
]);
app.directive('directiveTrue', [
    function () {
        return {
            restrict: 'EA',
            scope: true,
            template: 
                '<div>\
                    <p>\
                        <span>指令 scope: </span>\
                        <input type="text" ng-model="scopeTrue">\
                    </p>\
                </div>'
        };
    }
]);
app.directive('directiveObject', [
    function () {
        return {
            restrict: 'EA',
            scope: {},
            template: 
                '<div>\
                    <p>\
                        <span>指令 scope: </span>\
                        <input type="text" ng-model="scopeObject">\
                    </p>\
                </div>',
            link: function (scope) {
                // 由于使用独立scope,因此需要自己定义变量
                scope.scopeObject = 'Heron';
            }
        };
    }
]);
<div ng-controller="myCtrl">
    <h3>scope: false</h3>
    <p>
        <span>父 scope: </span>
        <input type="text" ng-model="scopeFalse">
    </p>
    <directive-false></directive-false>
    <h3>scope: true</h3>
    <p>
        <span>父 scope: </span>
        <input type="text" ng-model="scopeTrue">
    </p>
    <directive-true></directive-true>
    <h3>scope: {}</h3>
    <p>
        <span>父 scope: </span>
        <input type="text" ng-model="scopeObject">
    </p>
    <directive-object></directive-object>
</div>

运行结果如图:

指令scope运行结果

针对独立 scope,可以通过在对象中声明如何从外部传入参数。有以下三种绑定策略:

  • @ - 使用 DOM 属性值单项绑定到指令 scope 中。此时绑定的值总是一个字符串,因为 DOM 的属性值是一个字符串。

    <div my-directive age="26"></div>
    
    scope: {
        age: '@'
    }
  • = - 在父 scope 和指令 scope 之间建立双向绑定。

    <div my-directive age="age"></div>
    
    scope: {
        age: '='
    }
  • & - 使用父 scope 的上下文执行函数。一般用于绑定函数。

    <div my-directive sayHi="sayHi()"></div>
    
    scope: {
        sayHi: '&'
    }

绑定函数时,有时需要向指令外部传递参数,如下:

app.controller('myCtrl', [
    '$scope',
    '$cookieStore',
    function ($scope, $cookieStore) {
        $scope.name = 'Heron';

        $scope.sayHi = function (name, age) {
            alert('Hello ' + name + ', your age is ' + age);
        };
    }
]);

app.directive('myDirective', [
    function () {
        return {
            restrict: 'E',
            replace: true,
            scope: {
                clickMe: '&'
            },
            template: 
                '<div>\
                    <button class="btn btn-info" ng-click="clickMe({ age: age })">点我</button>\
                </div>',
            link: function (scope) {
                scope.age = 26;
            }
        };
    }
]);
<div ng-controller="myCtrl">
    <my-directive click-me="sayHi(name, age)"></my-directive>
</div>

运行结果如图:

指令向外部传递参数

说明一下:首先声明 clickMe: '&' 使用父 scope 的环境执行 clickMe 函数,然后在传递给指令时声明 click-me="sayHi(name, age)",表示父 scope 的 sayHi 方法需要两个参数,一个是 name,一个是 age,然后再指令中使用对象 {} 的方式向外传递参数,如 ng-click="clickMe({ age: age })",表示向指令外传递 age 参数,sayHi 方法从指令拿到 age 参数,再从自己的上下文中拿到 name 参数。

结语

AngularJS 指令的开发和使用千变万化,也有许多坑,希望大家留意,也希望大家能在评论区多多交流心得。

转载于:https://www.cnblogs.com/hetianqi/p/6408652.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30355437/article/details/98322817

智能推荐

使用JDBC连接数据库出现 The server time zone value ‘�й���׼ʱ��‘ is unrecognized or represents more than one解决方案_jdbc.properties timezone-程序员宅基地

文章浏览阅读553次。在 jdbc.properties 文件中的 url 后面加上 ?serverTimezone=UTC加入之前的jdbc.properties文件:user=rootpassword=12345678url=jdbc:mysql://localhost:3306/testdriverClass=com.mysql.cj.jdbc.Driver加入之后:user=rootpassword=12345678url=jdbc:mysql://localhost:3306/test?serv_jdbc.properties timezone

计算机图形学孔令德基础知识,计算机图形学基础教程孔令德答案-程序员宅基地

文章浏览阅读1.4k次。计算机图形学基础教程孔令德答案【篇一:大学计算机图形学课程设】息科学与工程学院课程设计任务书题目:小组成员:巴春华、焦国栋成员学号:专业班级:计算机科学与技术、2009级本2班课程:计算机图形学指导教师:燕孝飞职称:讲师完成时间: 2011年12 月----2011年 12 月枣庄学院信息科学与工程学院制2011年12 月20日课程设计任务书及成绩评定12【篇二:计算机动画】第一篇《计算机图形学》..._计算机图形学基础教程 孔令德 答案

python xlwings追加数据_大数据分析Python库xlwings提升Excel工作效率教程-程序员宅基地

文章浏览阅读1k次。原标题:大数据分析Python库xlwings提升Excel工作效率教程Excel在当今的企业中非常非常普遍。在AAA教育,我们通常建议出于很多原因使用代码,并且我们的许多数据科学课程旨在教授数据分析和数据科学的有效编码。但是,无论您偏爱使用大数据分析Python的程度如何,最终,有时都需要使用Excel来展示您的发现或共享数据。但这并不意味着仍然无法享受大数据分析Python的某些效率!实际上,..._xlwings通过索引添加数据

java8u211_jre864位u211-程序员宅基地

文章浏览阅读911次。iefans为用户提供的jre8 64位是针对64位windows平台而开发的java运行环境软件,全称为java se runtime environment 8,包括Java虚拟机、Java核心类库和支持文件,不包含开发工具--编译器、调试器和其它工具。jre需要辅助软件--JavaPlug-in--以便在浏览器中运行applet。本次小编带来的是jre8 64位官方版下载,版本小号u211版..._jre8是什么

kasp技术原理_KASP基因分型-程序员宅基地

文章浏览阅读5k次。KASP基因分型介绍KASP(Kompetitive Allele-Specific PCR),即竞争性等位基因特异性PCR,原理上与TaqMan检测法类似,都是基于终端荧光信号的读取判断,每孔反应都是采用双色荧光检测一个SNP位点的两种基因型,不同的SNP对应着不同的荧光信号。KASP技术与TaqMan法类似,它与TaqMan技术不同的是,它不需要每个SNP位点都合成特异的荧光引物,它基于独特的..._kasp是什么

华为p50预装鸿蒙系统,华为p50会不会预装鸿蒙系统_华为p50会预装鸿蒙系统吗-程序员宅基地

文章浏览阅读154次。华为现在比较火的还真就是新开发的鸿蒙系统了,那么在即将上市的华为p50手机上会不会预装鸿蒙系统呢?接下来我们就来一起了解一下华为官方发布的最新消息吧。1.华为p50最新消息相信大家都知道,随着华为鸿蒙OS系统转正日期临近,似乎全网的花粉们都在关注华为鸿蒙OS系统优化、生态建设等等,直接忽略了不断延期发布的华为P50手机,如今华为P50系列手机终于传来了最新的好消息,在经过一系列方案修改以后,终于被..._华为手机p50直接预装鸿蒙系统

随便推点

python用什么软件编程好-初学python编程,有哪些不错的软件值得一用?-程序员宅基地

文章浏览阅读2.1k次。Python编程的软件其实许多,作为一门面向大众的编程言语,许多修正器都有对应的Python插件,当然,也有特地的PythonIDE软件,下面我简单引见几个不错的Python编程软件,既有修正器,也有IDE,感兴味的朋友可以本人下载查验一下:1.VSCode:这是一个轻量级的代码修正器,由微软规划研发,免费、开源、跨途径,轻盈活络,界面精练,支撑常见的自动补全、语法提示、代码高亮、Git等功用,插..._python入门学什么好

pytorch一步一步在VGG16上训练自己的数据集_torch vgg训练自己的数据集-程序员宅基地

文章浏览阅读3.2w次,点赞30次,收藏307次。准备数据集及加载,ImageFolder在很多机器学习或者深度学习的任务中,往往我们要提供自己的图片。也就是说我们的数据集不是预先处理好的,像mnist,cifar10等它已经给你处理好了,更多的是原始的图片。比如我们以猫狗分类为例。在data文件下,有两个分别为train和val的文件夹。然后train下是cat和dog两个文件夹,里面存的是自己的图片数据,val文件夹同train。这样我们的..._torch vgg训练自己的数据集

毕业论文管理系统设计与实现(论文+源码)_kaic_论文系统设计法-程序员宅基地

文章浏览阅读968次。论文+系统+远程调试+重复率低+二次开发+毕业设计_论文系统设计法

在python2与python3中转义字符_Python 炫技操作:五种 Python 转义表示法-程序员宅基地

文章浏览阅读134次。1. 为什么要有转义?ASCII 表中一共有 128 个字符。这里面有我们非常熟悉的字母、数字、标点符号,这些都可以从我们的键盘中输出。除此之外,还有一些非常特殊的字符,这些字符,我通常很难用键盘上的找到,比如制表符、响铃这种。为了能将那些特殊字符都能写入到字符串变量中,就规定了一个用于转义的字符 \ ,有了这个字符,你在字符串中看的字符,print 出来后就不一定你原来看到的了。举个例子>..._pytyhon2、python3对%转义吗

java jar 文件 路径问题_「问答」解决jar包运行时相对路径问题-程序员宅基地

文章浏览阅读1.3k次。我这几天需要做一个Java程序,需要通过jar的形式运行,还要生成文件。最终这个程序是要给被人用的,可能那个用的人还不懂代码。于是我面临一个问题:生成的文件一定不能存绝对路径。刚开始我想得很简单,打绝对路径改成相对路径不就行了吗?于是有了这样的代码:String path = "../test.txt";File file = new File(path);……这个写法本身并没有问题,直接运行代码..._jar启动文件路径中存在!

微信读书vscode插件_曾经我以为 VSCode 是程序员专属的工具,直到发现了这些……...-程序员宅基地

文章浏览阅读598次。如果你知道 VSCode,一说起它,你可能第一个想到的就是把它当做一个代码编辑器,而它的界面应该可能大概率是这样的——如果你恰好又是个程序员,那你可能经常会用到它,不管是 Python、JS 还是 C++ 等各种语言对应的文件,都可以用它来进行简单的编辑和整理,甚至是运行和 debug......但是今天要讲的显然不是这些,经过小美的多方研究,发现了即使是对于大多数并不了解 VSCode,也完全不..._vscode weixin read