簡體   English   中英

改進AngularJS指令代碼

[英]Improve AngularJS directive code

我寫了一個AngularJS指令,但我對它很新,我不知道我是否采用了“Angular方式”......

以下是我的代碼: http ://plnkr.co/edit/X1tOk4z8f6dCK3mfB7HP?p=preview

HTML:

<!DOCTYPE html>
<html ng-app="app">

<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<meta charset=utf-8 />
<title>Directive Test</title>
<script src="script.js"></script>
</head>

<body ng-controller="MainCtrl">

  <button id="button1" ng-click="dummyClickFoo()" wait-button="foo"><i></i> Foo</button>
  <button id="button2" ng-click="dummyClickBar()" wait-button="bar"><i></i> Bar</button>

</body>

</html>

JS:

app = angular.module('app', []);

app.controller('MainCtrl', function($scope) {
    $scope.dummyClickFoo = function() {
        $scope.startSpinner('foo');

        setTimeout(function() {
                $scope.stopSpinner('foo');
          }, 3000);
    };

    $scope.dummyClickBar = function() {
        $scope.startSpinner('bar');

        setTimeout(function() {
                $scope.stopSpinner('bar');
          }, 3000);
    };
});


app.directive('waitButton', function() {
    return {
        restrict: 'A',
        controller: ['$scope', '$element', function($scope, $element) {
            $scope.startSpinner = function(id) {
                var el = angular.element(document.querySelector('[wait-button="'+id+'"]'));
                el.children('i').text('searching...');
            };

            $scope.stopSpinner = function(id) {
                var el = angular.element(document.querySelector('[wait-button="'+id+'"]'));
                el.children('i').empty();
            };
        }]
    };
});

我發現document.querySelector('[wait-button="'+id+'"]')部分,它有點“討厭”......(或不是?); 否則我不知道在同一個控制器中不同時間重復使用同一指令的更好方法。 有人可以建議我更好的代碼嗎?

謝謝。

訪問指令中的元素

我主張使用link函數來處理這類事情:

link: function($scope, elem, attrs){ /* do something w. elem */ }

在控制器中訪問元素並不是很有角度 這是指令對象的linkcompile功能的全部要點....

......但在極少數情況下,這是合理的。 控制器中注入的$element引用了與angular.element(document.querySelector('[wait-button="'+id+'"]'))代碼相同的內容。 此時您只需要使用$element 但我可以推薦一種更有棱角的方法嗎?

溝通。 控制器和指令

另一個問題是你如何將你的意圖從指令傳達到主控制器並返回到指令。 您的用例與大多數用例略有不同,因為您具有異步性質。

我已經做了一個利用隔離范圍和回調參數的例子。 在大多數現實場景中,您將處理異步回調的承諾。 因此,我使用.finally邏輯來執行回調,該回調與指令進行通信,無論異步邏輯是什么。

在我的例子中要記住的事情:

  • 我使用了coffeescript,因為我這樣編碼很好
  • 我用CSS / DOM開車怎么指令的加載狀態應該會出現,而不是試圖以編程方式做到這一點。 在我的書中,程序化DOM操作非常反NG。 指令為您提供足夠的聲明性地執行此類操作。
  • 我沒有使用指令控制器,因為除非你要為你的指令使用模板,否則你真的不需要自定義控制器。 當你使用link函數而不是自定義指令控制器時,有一個模糊的線。
  • 哦......我使用*控制器作為語法,因為如果你讀到關於NG的去向的任何內容,他們就會偏離整個$scope范式。

plunker - http://plnkr.co/edit/0AvlCQW5qqkpYKl2WpB3?p=preview

聲明的ui

主控制器

.controller 'MainCtrl', class MainCtrl
  @$inject = [
    '$scope'
    '$interval'
  ]

  constructor: ($scope, @$interval)->
    @viewData = 'Skynet 2.0'
    @isLoading = false

  callbackExample: ($callbackFunc)->
    @loadRqst()
    .finally -> $callbackFunc?()

  loadRqst: ->
    @isLoading = 1
    # this returns a promise which gets processed in the example functions
    @$interval => 
      console.log @isLoading++
    , 250, 10 
    .finally => 
      @isLoading = false

實施ui

<button callback-btn="vc.callbackExample($callbackFunc)">
  Callback Example<i> - I'm loading & I'm #1</i>
</button>

<button callback-btn="vc.callbackExample($callbackFunc)">
  Callback Example<i> - Look I can load too, I'm #2</i>
</button>

CSS

[callback-btn] i{
  display: none;
}

[callback-btn].loading i{
  display: initial;
}

指令

.directive 'callbackBtn', ($parse)->
  dir =
    restrict: 'A' 
    scope: { callbackBtn: '&' }
    link: ($scope, elem, attrs)->

      onCallback = ->
        console.log 'on callback'
        elem.removeClass 'loading'

      elem.on 'click', ->
        elem.addClass 'loading'
        $scope.$apply ->
          $scope.callbackBtn({$callbackFunc: onCallback})

我強烈建議你轉換

<button id="button1" ng-click="dummyClickFoo()" wait-button="foo"><i></i> Foo</button>

到一個指令,所以你的代碼將是

<my-button  label="foo"></my-button>

directive的整個想法是促進關注點的分離。

當你使用指令時,它的所有功能都應該由指令本身來處理。

現在,你的MainCtrl有一部分指令邏輯,理想情況下你的指令應該在那里。

此外,在您的指令中,還有一個控制器功能。 理想情況下,控制器功能應該只處理視圖模型之間傳遞的數據等。

對於DOM正在進行的操作,它應該在link函數中實現。

因此,做同樣事情的angular way如下。

你的Html

<body ng-controller="MainCtrl">

  <button id="button1" wait-button="foo"><i></i> Foo</button>
  <button id="button2" wait-button="bar"><i></i> Bar</button>
  <!-- NOTICE: No ng-click handlers here -->
</body>

你的MainCtrl

app.controller('MainCtrl', function($scope) {
    // No code required here. This will be handled in Directive's link function.
});

你的waitButton指令。

    app.directive('waitButton', function() {
        return {
            restrict: 'A',
            controller: ['$scope', '$element', function($scope, $element) {
//Again, it's not controller's job to handle DOM manipulations. So code required here.

            }],
            link: function($scope, $element){
              var waitButtons = angular.element(document.querySelectorAll('[wait-button]'));// NOTE: I've used querySelectorAll instead of querySelector. This will make this function generic.
              waitButtons.on('click', function(){
                var $this = angular.element(this);
                startSpinner($this);
                setTimeout(function(){
                  stopSpinner($this);
                },3000);
              });

               function startSpinner(el) {
                    el.children('i').text('searching...');
                }

               function stopSpinner(el) {
                    el.children('i').empty();
                }

            }
        };
    });

將您的函數移動到指令中。 將單擊處理程序放在鏈接函數中。

app.directive('waitButton', function($timeout) {
    return {
        restrict: 'A',
        link: function (scope, elem, attrs) {
                   var startSpinner = function() {
                       elem.children('i').text('searching...');
                   };
                   var stopSpinner = function() {
                       elem.children('i').empty();
                   };
                   var clickHandler = function() {
                       startSpinner();
                       $timeout(stopSpinner,3000);
                   };
                   elem.on("click", clickHandler);
               }
     }
});

還可以使用AngularJS $timeout服務。 有關它的更多信息,請參閱AngularJS $超時服務API參考

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM