angularJs中自定義directive的數據交互


首先放官方文檔地址:https://docs.angularjs.org/guide/directive

 

  就我對directive的粗淺理解,它一般用於獨立Dom元素的封裝,應用場合為控件重用和邏輯模塊分離。后者我暫時沒接觸,但數據交互部分卻是一樣的。所以舉幾個前者的例子,以備以后忘記。

  directive本身的作用域$scope可以選擇是否封閉,不封閉則和其controller共用一個作用域$scope。例子如下:

 1 <body ng-app="myApp" ng-controller="myCtrl">
 2 <test-directive></test-directive>
 3 <script>
 4     angular.module("myApp",[])
 5             .controller("myCtrl",function($scope){
 6                 $scope.data = {
 7                     name:"白衣如花"
 8                 };
 9             })
10             .directive("testDirective",function(){
11                 return {
12                     restrict:"E",
13                     template:"<h1>{{data.name||'未定義'}}</h1>"
14                 }
15             });
16 </script>
17 </body>

  顯示結果為:白衣如花,可以知道directive中的data.name就是myCtrl控制器中的$scope.data.name。

 

  那么封閉的directive呢?怎么封閉,封閉效果是什么樣的,封閉后怎么數據交互?這些都是我這幾天摸索的東西。

 1 <body ng-app="myApp" ng-controller="myCtrl">
 2 <test-directive></test-directive>
 3 <script>
 4     angular.module("myApp",[])
 5             .controller("myCtrl",function($scope){
 6                 $scope.data = {
 7                     name:"白衣如花"
 8                 };
 9             })
10             .directive("testDirective",function(){
11                 return {
12                     restrict:"E",
13                     scope: {},
14                     template:"<h1>{{data.name||'未定義'}}</h1>"
15                 }
16             });
17 </script>
18 </body>

結果顯示為:未定義。所以在directive定義時,添加屬性scope就可以把directive的作用域和父控制器的作用域分離開來。

 

好,了解了開放和封閉之后,進入主題,如何進行數據交互。個人覺得數據交互分為:父控制器獲取directive的變量;directive獲取父控制器的變量;父控制器調用directive的函數;directive調用父控制器的函數。

 

1.父控制器獲取directive的變量。比如封裝了一個輸入框接受用戶輸入,父控制器點擊搜索按鈕要獲取用戶輸入:

 1 <body ng-app="myApp" ng-controller="myCtrl">
 2 <p>名字:{{outerName}}</p>
 3 <test-directive inner-name="outerName"></test-directive>
 4 <script>
 5     angular.module("myApp",[])
 6             .controller("myCtrl",function($scope){
 7             })
 8             .directive("testDirective",function(){
 9                 return {
10                     restrict:"E",
11                     scope: {
12                         innerName: "="
13                     },
14                     template:"<input type='text' ng-model='innerName' placeholder='白衣如花'>"
15                 }
16             });
17 </script>
18 </body>

 

顯示結果如下:

分析:從數據流向說起,testDirective中的一個input輸入綁定在innerName中,innerName是directive私有作用域擁有的變量,外部控制器不能直接用。通過innerName: "="傳遞給html中的inner-name屬性,

而inner-name屬性則綁定在外部控制器的outerName變量中,所以最后顯示在最上面的<p>標簽內。上述代碼等價於如下代碼:

<test-directive name="outerName"></test-directive>
scope: {
    innerName: "=name"
},

 

 由inerName: "="變成了innerName: "=name",而html屬性綁定也由inner-name變成了name。

 

2.directive獲取父控制器的變量。這個應用場合應該挺多的,比如公共的頁眉頁腳,公共的展示面板等。

這個用上面例子的"="一樣可以實現,於是我們知道了"="是雙向綁定。但是我們要防止directive內部意外修改數據該怎么辦呢?於是單向綁定"@"就出場了。

 1 <body ng-app="myApp" ng-controller="myCtrl">
 2 <input type='text' ng-model='outerName' placeholder='白衣如花'>
 3 <test-directive inner-name="{{outerName}}"></test-directive>
 4 <script>
 5     angular.module("myApp",[])
 6             .controller("myCtrl",function($scope){
 7             })
 8             .directive("testDirective",function(){
 9                 return {
10                     restrict:"E",
11                     scope: {
12                         innerName: "@"
13                     },
14                     template:"<p>名字:{{innerName}}</p>" +
15                     "<button ng-click='innerName=innerName+1'>點擊</button>"
16                 }
17             });
18 </script>
19 </body>

 

值得注意的是:@在html的屬性綁定時需要{{}}開標識,而=則不用。我的理解是,對於父控制器而言,@是數據傳遞,而=是數據綁定,所以有這些區別。directive中加入了一個按鈕用於驗證修改數據后

父控制器是否發生改變,結果是=有變化,@無變化,很容易得出結論:=是雙向綁定,@是單向綁定。

 

3.directive調用父控制器的函數。應用場合,暫時想不到(汗)。

變量用=和@來傳遞,函數則用&。例子如下:

 1 <body ng-app="myApp" ng-controller="myCtrl">
 2 <p>名字:{{outerName}}</p>
 3 <test-directive on-click="click(name)"></test-directive>
 4 <script>
 5     angular.module("myApp",[])
 6             .controller("myCtrl",function($scope){
 7                 $scope.click = function (name) {
 8                     $scope.outerName = name || "白衣如花";
 9                 }
10             })
11             .directive("testDirective",function(){
12                 return {
13                     restrict:"E",
14                     scope: {
15                         onClick: "&"
16                     },
17                     template:"<input type='text' ng-model='innerName' placeholder='白衣如花'>" +
18                     "<button ng-click='onClick({name: innerName})'>點擊</button>"
19                 }
20             });
21 </script>
22 </body>

 

數據傳遞流程和之上的例子差不多,唯一要注意的是參數傳遞時,{name: innerName}前者是形參,后者是實參。多個參數時,參數順序不重要,形參一一對應。

 

4.父控制器調用directive的函數。這個是前段時間遇到的難點,情況較其他復雜一些。應用場合也很普遍,比如初始化,重置等。

 1 <body ng-app="myApp" ng-controller="myCtrl">
 2 <button ng-click="click()">重置</button>
 3 <test-directive action="action"></test-directive>
 4 <script>
 5     angular.module("myApp",[])
 6             .controller("myCtrl",function($scope){
 7                 $scope.action = {};
 8                 $scope.click = function () {
 9                     $scope.action.reset();
10                 }
11             })
12             .directive("testDirective",function(){
13                 return {
14                     restrict:"E",
15                     scope: {
16                         action: "="
17                     },
18                     template:"<input type='text' ng-model='name' placeholder='白衣如花'>",
19                     controller: function ($scope) {
20                         $scope.action.reset = function () {
21                             $scope.name = "白衣如花"
22                         }
23                     }
24                 }
25             });
26 </script>
27 </body>

 

 又一次用到了=,利用了js中函數也是屬性的原理。似乎,理解了=的雙向綁定,就很容易調用directive內部函數了。但是初始化呢?

首先想到的是類似的=來引用傳遞:

 1 <body ng-app="myApp" ng-controller="myCtrl">
 2 <test-directive action="action"></test-directive>
 3 <script>
 4     angular.module("myApp",[])
 5             .controller("myCtrl",function($scope){
 6                 $scope.action = {};
 7                 $scope.action.init();
 8             })
 9             .directive("testDirective",function(){
10                 return {
11                     restrict:"E",
12                     scope: {
13                         action: "="
14                     },
15                     template:"<input type='text' ng-model='name' placeholder='白衣如花'>",
16                     controller: function ($scope) {
17                         $scope.action.init = function () {
18                             $scope.name = "白衣如花"
19                         }
20                     }
21                 }
22             });
23 </script>
24 </body>

 

但是運行卻發現,錯誤顯示$scope.action.init is not a function,看提示應該是運行到第7行的時候,$scope.action.init函數還未定義。怎么辦呢?把directive提到controller之前試試?一樣是錯誤。

 

嗯,可以不用函數,直接在directive的controller中執行$scope.name = "白衣如花",似乎很完美,但如果是有參數的初始化呢?事實上js分離后,我遇到的問題是根據http請求的返回結果來初始化directive,由於

網絡快慢不一定,導致控件初始化時不一定有http請求的返回(沒有有效的初始化參數),也不能保證http請求返回后directive已經初始化(不能用=來進行函數調用)。

 

需求很明了了,如果能監控參數變化,再執行初始化,此時能保證directive已經加載,而且有有效的參數。正好angularjs提供了$watch。代碼如下:

 1 <body ng-app="myApp" ng-controller="myCtrl">
 2 <test-directive action="action"></test-directive>
 3 <script>
 4     angular.module("myApp",[])
 5             .controller("myCtrl",function($scope){
 6                 $scope.action = {name: "白衣如花"};
 7             })
 8             .directive("testDirective",function(){
 9                 return {
10                     restrict:"E",
11                     scope: {
12                         action: "="
13                     },
14                     template:"<input type='text' ng-model='name' placeholder='白衣如花'>",
15                     link: function (scope, elem, attrs) {
16                         scope.$watch(attrs.action, function (value) {
17                             scope.action.init();
18                         })
19                     },
20                     controller: function ($scope) {
21                         $scope.action.init = function () {
22                             $scope.name = $scope.action.name
23                         }
24                     }
25                 }
26             });
27 </script>
28 </body>

 

這是我對於directive數據交互的粗淺理解。想要更詳細了解,請參看官方文檔:https://docs.angularjs.org/guide/directive


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM