ホームページ  >  記事  >  ウェブフロントエンド  >  Angular でのディレクティブの使用法の詳細な分析

Angular でのディレクティブの使用法の詳細な分析

青灯夜游
青灯夜游転載
2021-04-13 10:45:362368ブラウズ

この記事では、Angular ディレクティブについて詳しく紹介し、その使用法を理解します。一定の参考値があるので、困っている友達が参考になれば幸いです。

Angular でのディレクティブの使用法の詳細な分析

Angular ディレクティブの学習

学習目的: ng ディレクティブの使用方法をより深く理解すること。

ディレクティブは、AngularJS ではさらに複雑になる可能性があります。一般的には、それは指示として理解されます。 AngularJS には、ng-app、ng-controller などの多くのプリセット命令が付属しています。 AngularJS に付属の説明書はすべて ng- で始まります。

それでは、ディレクティブとは一体何なのでしょうか?私の個人的な理解は次のとおりです。HTML と JS の一部を一緒にカプセル化して、特定の機能を備えた再利用可能な独立したエンティティを形成します。 Directive の一般的な使い方を詳しく説明します。

AnguarJS ディレクティブの一般的な定義形式とパラメーターの説明

次のコードを見てください:

var myDirective = angular.module('directives', []);

myDirective.directive('directiveName', function($inject) {
    return {
        template: '<div></div>',
        replace: false,
        transclude: true,
        restrict: 'E',
        scope: {},
        controller: function($scope, $element) {

        },
        complie: function(tElement, tAttrs, transclude) {
            return {
                pre: function preLink(scope, iElement, iAttrs, controller) {

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

                }
            };
        },
        link: function(scope, iElement, iAttrs) {

        }
    };
});
  • ここではオブジェクトが直接返され、オブジェクト比較が含まれます。 複数の属性。これらの属性はカスタム ディレクティブの定義です。詳しい意味は後述します。
  • 戻りオブジェクト パラメーターの説明
return {
    name: '',
    priority: 0,
    terminal: true,
    scope: {},
    controller: fn,
    require: fn,
    restrict: '',
    template: '',
    templateUrl: '',
    replace: '',
    transclude: true,
    compile: fn,
    link: fn
}

関連チュートリアルの推奨事項: "angular チュートリアル"

上記のように、多くの属性があります。この属性行はディレクティブを定義するために使用されます。

それぞれの機能を一つずつ説明していきましょう。

  • name

    • は現在のスコープの名前を表します。通常、宣言時にデフォルト値が使用され、このプロパティを手動で設定する必要があります。
  • 優先度

    • 優先度。同じ DOM 要素に複数のディレクティブが定義されている場合、それらの実行順序を指定することが必要になる場合があります。この属性は、ディレクティブのコンパイル関数が呼び出される前にソートするために使用されます。優先度が同じ場合、実行順序は不定です(経験上、優先度が高い方が最初に実行され、優先度が同じ場合は最初にバインドされてから実行されます)。
  • ターミナル

    • 最後のグループ。 true に設定すると、現在の優先順位が実行されるディレクティブの最後のグループになることを意味します。つまり、このディレクティブよりも優先順位の低いディレクティブは実行されません。同じ優先順位が引き続き実行されますが、順序は不確かです。
  • #scope

    • true
        はこれに対するディレクティブを作成しますディレクティブの新しいスコープ。同じ要素内に新しいスコープを必要とする複数のディレクティブがある場合でも、スコープは 1 つだけ作成されます。ルート テンプレートは新しいスコープを取得する傾向があるため、新しいスコープ ルールはルート テンプレートには適用されません。
    • {}
        は、新しい独立したスコープを作成します。このスコープと一般的なスコープの違いは、スコープを継承しないことです。親スコープのプロトタイプ。これは、再利用可能なコンポーネントを作成するのに役立ち、親スコープのデータが読み取られたり変更されたりするのを効果的に防ぐことができます。この独立したスコープは、親スコープから派生したローカル スコープ プロパティのセットを含むハッシュ セットを作成します。これらのローカル スコープ プロパティは、テンプレートが値のエイリアスを作成するのに役立ちます。ローカルの定義は、ローカル スコープのプロパティのセットをソースにハッシュ マッピングしたものです。
  • #コントローラー

    コントローラー コンストラクター。コントローラーはプリリンク手順の前に初期化され、指定された名前の require を通じて他のディレクティブを共有できるようになります。これにより、ディレクティブが相互に通信し、互いの動作を強化できるようになります。コントローラーはデフォルトで次のローカル オブジェクトを挿入します。
    • $scope 現在の要素と結合されたスコープ
      • $element 現在の要素
      • $attrs 現在の要素の属性オブジェクトelement
      • $transclude 現在のスコープに事前にバインドされている転置リンク関数
  • #require
  • 別のコントローラーをリクエストし、それを現在のディレクティブのリンク関数に渡します。 require はディレクティブ コントローラーの名前を渡す必要があります。この名前に対応するコントローラーが見つからない場合は、エラーがスローされます。名前には次のプレフィックスを付けることができます:

      ? 例外をスローしません。これにより、この依存関係がオプションになります
    • #^ 親要素のコントローラーを検索できるようにします
    • ##restrict
  • ディレクティブを指定された宣言メソッドに制限する EACM のサブセットである文字列。省略した場合、ディレクティブは属性を介した宣言のみを許可します E 要素名:

      A 属性名:
      • C クラス名:
      • M コメント:
      #template
  • replace が true の場合、テンプレートのコンテンツは現在の HTML 要素を取得し、元の要素の属性とクラスを一緒に転送します。replace が false の場合、テンプレート要素は現在の要素の子要素として扱われます。

    • テンプレート URL
    • 与template基本一致,但模版通过指定的url进行加载。因为模版加载是异步的,所有compilation、linking都会暂停,等待加载完毕后再执行。
  • replace

    • 如果设置为true,那么模版将会替换当前元素,而不是作为子元素添加到当前元素中。(为true时,模版必须有一个根节点)
  • transclude

    • 编译元素的内容,使它能够被directive使用。需要在模版中配合ngTransclude使用。transclusion的有点是linking function能够得到一个预先与当前scope绑定的transclusion function。一般地,建立一个widget,创建独立scope,transclusion不是子级的,而是独立scope的兄弟级。这将使得widget拥有私有的状态,transclusion会被绑定到父级scope中。(上面那段话没看懂。但实际实验中,如果通过调用myDirective,而transclude设置为true或者字符串且template中包含的时候,将会将的编译结果插入到sometag的内容中。如果any的内容没有被标签包裹,那么结果sometag中将会多了一个span。如果本来有其他东西包裹的话,将维持原状。但如果transclude设置为’element’的话,any的整体内容会出现在sometag中,且被p包裹)
      • true/false 转换这个directive的内容。(这个感觉上,是直接将内容编译后搬入指定地方)
      • ‘element’ 转换整个元素,包括其他优先级较低的directive。(像将整体内容编译后,当作一个整体(外面再包裹p),插入到指定地方)
  • compile

    • 这里是compile function,将在下面实例详细说明
  • link

    • 这里是link function ,将在下面实例详细讲解。这个属性仅仅是在compile属性没有定义的情况下使用。

关于scope

这里关于directive的scope为一个object时,有更多的内容非常有必要说明一下。看下面的代码:

scope: {
    name: '=',
    age: '=',
    sex: '@',
    say: '&'
}

这个scope中关于各种属性的配置出现了一些奇怪的前缀符号,有=,@,&,那么这些符号具体的含义是什么呢?再看下面的代码:

  • html
<div my-directive name="myName" age="myAge" sex="male" say="say()"></div>复制代码
  • javascript
function Controller($scope) {
    $scope.name = 'Pajjket';
    $scope.age = 99;
    $scope.sex = '我是男的';
    $scope.say = function() {
        alert('Hello,我是弹出消息');
    };
}
可以看出,几种修饰前缀符的大概含义:
  • =: 指令中的属性取值为Controller中对应$scope上属性的取值
  • @: 指令中的取值为html中的字面量/直接量
  • &: 指令中的取值为Controller中对应$scope上的属性,但是这个属性必须为一个函数回调 下面是更加官方的解释:
  • =或者=expression/attr

在本地scope属性与parent scope属性之间设置双向的绑定。如果没有指定attr名称,那么本地名称将与属性名称一致。

  • 例如: 中,widget定义的scope为:{localModel: '=myAttr'},那么widget scope property中的localName将会映射父scope的parentModel。如果parentModel发生任何改变,localModel也会发生改变,反之亦然。即双向绑定。

  • @或者@attr 建立一个local scope property到DOM属性的绑定。因为属性值总是String类型,所以这个值总返回一个字符串。如果没有通过@attr指定属性名称,那么本地名称将与DOM属性的名称一致。 例如: ,widget的scope定义为:{localName: '@myAttr'}。那么,widget scope property的localName会映射出"hello "转换后的真实值。当name属性值发生改变后,widget scope的localName属性也会相应的改变(仅仅是单向,与上面的=不同)。那么属性是在父scope读取的(不是从组件的scope读取的)

  • &或者&attr 提供一个在父scope上下文中执行一个表达式的途径。如果没有指定attr的名称,那么local name将与属性名一致。

    • 例如:

68c72eacde80dbb19dac8db1a79aac0a,widget的scope定义为:{localFn:’increment()’},那么isolate scope property localFn会指向一个包裹着increment()表达式的function。 一般来说,我们希望通过一个表达式,将数据从isolate scope传到parent scope中。这可以通过传送一个本地变量键值的映射到表达式的wrapper函数中来完成。例如,如果表达式是increment(amount),那么我们可以通过localFn({amount:22})的方式调用localFn以指定amount的值。

directive 实例讲解

下面的示例都围绕着上面所作的参数说明而展开的。

  • directive声明实例
// 自定义directive
var myDirective = angular.modeule('directives', []);

myDirective.directive('myTest', function() {
    return {
        restrict: 'EMAC',
        require: '^ngModel',
        scope: {
            ngModel: '='
        },
        template: '<div><h4>Weather for {{ngModel}}</h4</div>'
    };
});

// 定义controller
var myControllers = angular.module('controllers', []);
myControllers.controller('testController', [
    '$scope',
    function($scope) {
        $scope.name = 'this is directive1';
    }
]);


var app = angular.module('testApp', [
    'directives',
    'controllers'
]);

<body ng-app="testApp">
    <div ng-controller="testController">
        <input type="text" ng-model="city" placeholder="Enter a city" />
        <my-test ng-model="city" ></my-test>
        <span my-test="exp" ng-model="city"></span>
        <span ng-model="city"></span>
    </div>
</body>

template与templateUrl的区别和联系

templateUrl其实根template功能是一样的,只不过templateUrl加载一个html文件,上例中,我们也能发现问题,template后面根的是html的标签,如果标签很多呢,那就比较不爽了。可以将上例中的,template改一下。

myDirective.directive('myTest', function() {
    return {
        restrict: 'EMAC',
        require: '^ngModel',
        scope: {
            ngModel: '='
        },
        templateUrl:'../partials/tem1.html'   //tem1.html中的内容就是上例中template的内容。
    }
});

scope重定义

//directives.js中定义myAttr
myDirectives.directive('myAttr', function() {
    return {
        restrict: 'E',
        scope: {
            customerInfo: '=info'
        },
        template: 'Name: {{customerInfo.name}} Address: {{customerInfo.address}}<br>' +
                  'Name: {{vojta.name}} Address: {{vojta.address}}'
    };
});

//controller.js中定义attrtest
myControllers.controller('attrtest',['$scope',
    function($scope) {
        $scope.naomi = {
            name: 'Naomi',
            address: '1600 Amphitheatre'
        };
        $scope.vojta = {
            name: 'Vojta',
            address: '3456 Somewhere Else'
        };
    }
]);

// html中
<body ng-app="testApp">
    <div ng-controller="attrtest">
        <my-attr info="naomi"></my-attr>
    </div>
</body>

其运行结果如下:

Name: Naomi Address: 1600 Amphitheatre      //有值,因为customerInfo定义过的
Name: Address:                              //没值 ,因为scope重定义后,vojta是没有定义的

我们将上面的directive简单的改一下,

myDirectives.directive('myAttr', function() {
    return {
        restrict: 'E',
        template: 'Name: {{customerInfo.name}} Address: {{customerInfo.address}}<br>' +
                  'Name: {{vojta.name}} Address: {{vojta.address}}'
    };
});
  • 运行结果如下:
Name: Address:
Name: Vojta Address: 3456 Somewhere Else

因为此时的directive没有定义独立的scope,customerInfo是undefined,所以结果正好与上面相反。

transclude的使用

  • transclude的用法,有点像jquery里面的$().html()功能
myDirective.directive('myEvent', function() {
    return {
        restrict: 'E',
        transclude: true,
        scope: {
            'close': '$onClick'      //根html中的on-click="hideDialog()"有关联关系
        },
        templateUrl: '../partials/event_part.html'
    };
});

myController.controller('eventTest', [
    '$scope',
    '$timeout',
    function($scope, $timeout) {
        $scope.name = 'Tobias';
        $scope.hideDialog = function() {
            $scope.dialogIsHidden = true;
            $timeout(function() {
                $scope.dialogIsHidden = false;
            }, 2000);
        };
    }
]);
<body ng-app="phonecatApp">
    <div ng-controller="eventtest">
        <my-event ng-hide="dialogIsHidden" on-click="hideDialog()">
            Check out the contents, {{name}}!
        </my-event>
    </div>
</body>

<!--event_part.html -->
<div>
    <a href ng-click="close()">×</a>
    <div ng-transclude></div>
</div>
  • 说明:这段html最终的结构应该如下所示:
<body ng-app="phonecatApp">
    <div ng-controller="eventtest">
        <div ng-hide="dialogIsHidden" on-click="hideDialog()">
            <span>Check out the contents, {{name}}!</span>
        </div>
    </div>
</body>
  • 将原来的html元素中的元素Check out the contents, !插入到模版的中,还会另外附加一个标签。controllerlinkcompile之间的关系
myDirective.directive('exampleDirective', function() {
    return {
        restrict: 'E',
        template: '<p>Hello {{number}}!</p>',
        controller: function($scope, $element){
            $scope.number = $scope.number + "22222 ";
        },
        link: function(scope, el, attr) {
            scope.number = scope.number + "33333 ";
        },
        compile: function(element, attributes) {
            return {
                pre: function preLink(scope, element, attributes) {
                    scope.number = scope.number + "44444 ";
                },
                post: function postLink(scope, element, attributes) {
                    scope.number = scope.number + "55555 ";
                }
            };
        }
    }
});

//controller.js添加
myController.controller('directive2',[
    '$scope',
    function($scope) {
        $scope.number = '1111 ';
    }
]);

//html
<body ng-app="testApp">
    <div ng-controller="directive2">
        <example-directive></example-directive>
    </div>
</body>
  • 上面小例子的运行结果如下:
Hello 1111 22222 44444 5555 !

由结果可以看出来,controller先运行,compile后运行,link不运行。 我们现在将compile属性注释掉后,得到的运行结果如下:Hello 1111 22222 33333 !

由结果可以看出来,controller先运行,link后运行,link和compile不兼容。一般地,compile比link的优先级要高。

更多编程相关知识,请访问:编程入门!!

以上がAngular でのディレクティブの使用法の詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。