帶你走近AngularJS - 創建自定義指令


帶你走近AngularJS系列:

  1. 帶你走近AngularJS - 基本功能介紹
  2. 帶你走近AngularJS - 體驗指令實例
  3. 帶你走近AngularJS - 創建自定義指令

------------------------------------------------------------------------------------------------

為什么使用AngularJS 指令?

使用過 AngularJS 的朋友應該最感興趣的是它的指令。現今市場上的前端框架也只有AngularJS 擁有自定義指令的功能,並且AngularJS 是目前唯一提供Web應用可復用能力的框架。

目前有很多JavaScript 產品提供插件給Web開發人員。例如, Bootstrap 就是當前比較流行的提供樣式和JavaScript插件的前端開發工具包。但是開發人員在使用Booostrap中的插件時, 必須切換到JavaScript 模式來寫 jQuery 代碼來激活插件雖然jQuery 代碼寫起來十分簡單,但是必須和HTML進行同步,這是一個單調乏味且容易出錯的過程。

AngularJS主頁展示了一個簡單的例子,用於實現Bootstrap中的 Tab功能,可以在頁面中輕松添加 Tab 功能,並且使用方法和 ul 標簽一樣簡單。HTML代碼如下:

<body ng-app="components"> 
  <h3>BootStrap Tab Component</h3> 
  <tabs> 
    <pane title="First Tab"> 
      <div>This is the content of the first tab.</div> 
    </pane> 
    <pane title="Second Tab"> 
      <div>This is the content of the second tab.</div> 
    </pane> 
  </tabs> 
</body>

 

JavaScript代碼如下:

angular.module('components', []). 
  directive('tabs', function() { 
    return { 
      restrict: 'E', 
      transclude: true, 
      scope: {}, 
      controller: [ "$scope", function($scope) { 
        var panes = $scope.panes = []; 
  
        $scope.select = function(pane) { 
          angular.forEach(panes, function(pane) { 
            pane.selected = false; 
          }); 
          pane.selected = true; 
        } 
  
        this.addPane = function(pane) { 
          if (panes.length == 0) $scope.select(pane); 
          panes.push(pane); 
        } 
      }], 
      template: 
        '<div class="tabbable">' + 
          '<ul class="nav nav-tabs">' + 
            '<li ng-repeat="pane in panes" ng-class="{active:pane.selected}">'+ 
              '<a href="" ng-click="select(pane)">{{pane.title}}</a>' + 
            '</li>' + 
          '</ul>' + 
          '<div class="tab-content" ng-transclude></div>' + 
        '</div>', 
      replace: true 
    }; 
  }). 
  directive('pane', function() { 
    return { 
      require: '^tabs', 
      restrict: 'E', 
      transclude: true, 
      scope: { title: '@' }, 
      link: function(scope, element, attrs, tabsCtrl) { 
        tabsCtrl.addPane(scope); 
      }, 
      template: 
        '<div class="tab-pane" ng-class="{active: selected}" ng-transclude>' + 
        '</div>', 
      replace: true 
    }; 
  })

 

你可以從以下鏈接查看效果:http://jsfiddle.net/powertoolsteam/GBE7N/1/

image

正如你所見,除了擁有用於實現指令的 <tabs> 和<pane> 標簽,頁面和常規HTML頁面沒有什么區別。HTML開發人員無需編寫任何代碼。當然,總需要有第一個吃螃蟹的人,創建指令共享使用,但是目前Tabs指令已經很常見了,可以在任何地方復用(如BootStrap,、jQueryUIWijmo, 和一些知名的前端插件集)。

由於指令的易用和易編寫,許多用戶已經開始使用AngularJS編寫指令了。例如, AngularJS 開發組已經基於AngularJS實現了一系列指令-UI Bootstrap 來代替Bootstrap; 知名ComponentOne 控件廠商也在AngularJS 基礎上創建了Wijmo ;我們也可以在GitHub上找到一些公共指令資料庫:jQueryUI widgets

擁有了 AngularJS,是不是覺得自己已經站在了巨人的肩膀上了?但是不要高興的太早,如果已經有了這么多的指令供我們使用,那我們為什么還要學習AngularJS ,為什么還要學習自定義指令呢?

舉個簡單的例子,也許你有特殊的需求:假設你在一家財務公司工作,你需要創建一張財務表單,它需要以表格的形式展示數據、擁有綁定、編輯、校驗並且同步數據更新到服務器的功能。表單插件很常見但是能夠滿足這些具體需求的不得而知了,所以你必須根據實際業務需求來創建自定義指令。

<body ng-app="abcFinance"> 
  <h3>Offshore Investment Summary</h3> 
  <abc-investment-form 
    customer="currentCustomer" 
    country="currentCountry"> 
  </abc-investment-form data> 
</body> 

 

這就是本篇文章的目的,接下來我們會討論如何創建 AngularJS指令。

 

創建自定義AngularJS 指令

文章開頭的自定義指令十分的簡單。它僅僅實現了同步的功能。一般指令是包含更多元素的:

//創建指令模塊 (或者檢索現有模塊) 
var m = angular.module("myApp");

// 創建"my-dir"指令 
myApp.directive("myDir", function() { 
  return { 
    restrict: "E",        // 指令是一個元素 (並非屬性) 
    scope: {              // 設置指令對於的scope 
      name: "@",          // name 值傳遞 (字符串,單向綁定) 
      amount: "=",        // amount 引用傳遞(雙向綁定) 
      save: "&"           // 保存操作 
    }, 
    template:             // 替換HTML (使用scope中的變量) 
      "<div>" + 
      "  {{name}}: <input ng-model='amount' />" + 
      "  <button ng-click='save()'>Save</button>" + 
      "</div>", 
    replace: true,        // 使用模板替換原始標記 
    transclude: false,    // 不復制原始HTML內容 
    controller: [ "$scope", function ($scope) { …  }], 
    link: function (scope, element, attrs, controller) {…} 
  } 
});  

 

效果如下:

image


注意這個自定義指令遵循一種格式:以"my" 為前綴,類似於命名空間,因此如果你在應用中引用了多個模塊指令,你可以通過前綴很容易的判斷出它是在哪定義的。這不是硬性要求,但是這樣做可以帶來很多便利。

指令的構造函數會返回帶有屬性的JavaScript 對象。這些內容在AngularJS 主頁中都有清晰說明。以下是我對一些屬性的理解:

  1. restrict: 說明指令在HTML中的應用形式,備選項有"A"、"E" 和 "C", "M" ,分別代表 attribute、element、class和comment(默認值為"A")。我們將更多的關注attributes-如何創建UI元素。
  2. scope: 創建指令的作用范圍,scope在指令中作為屬性標簽傳遞。Scope 是創建可以復用指令的必要條件,每個指令(不論是處於嵌套指令的哪一級)都有其唯一的作用域,它不依賴於父scope。scope 對象定義names 和types 變量。上面的例子即創建了3個scope變量。
    • name: "@" (值傳遞,單向綁定):
      "@"符號表示變量是值傳遞。指令會檢索從父級scope中傳遞而來字符串中的值。指令可以使用該值但無法修改,是最常用的變量。
    • amount: "=" (引用,雙向綁定)
      "="符號表示變量是引用傳遞。指令檢索主Scope中的引用取值。值可以是任意類型的,包括復合對象和數組。指令可以更改父級Scope中的值,所以當指令需要修改父級Scope中的值時我們就需要使用這種類型。
    • save: "&" (表達式)
      “&”符號表示變量是在父級Scope中啟作用的表達式。它允許指令實現比修改值更高級的操作。
  3. template: 替代原始模板中的標記的字符串。替換功能將替換所有舊元素為新值。注意template是如何使用Scope中定義的變量的。這允許你無需寫任何額外的代碼即可創建macro-style 風格指令。replace: 說明是否替換原始標記中的值或是追加原始標記中的值。默認值是false,這時原始標記將被保留。
  4. transclude: 說明自定義指令是否復制原始標記中的內容。例如,之前展示的“tab”指令設置了transclude 為 true,因為tab 元素包含其他HTML 元素。 "dateInput" 指令則需要在初始化時為空,所以需要設置transclude 為false。
  5. link: 該方法在指令中扮演着重要的角色。它負責執行DOM 操作和注冊事件監聽器等。link 方法包含以下參數:
    • scope: 指令Scope的引用。scope 變量在初始化時是不被定義的,link 方法會注冊監視器監視值變化事件。
    • element: 包含指令的DOM元素的引用, link 方法一般通過jQuery 操作實例(如果沒有加載jQuery,還可以使用Angular's jqLite )。
    • controller: 在有嵌套指令的情況下使用。這個參數作用在於把子指令的引用提供給父指令,允許指令之間進行交互, tab 指令就是使用該參數較典型的例子:http://jsfiddle.net/powertoolsteam/GBE7N/1/

注意,當調用link 方法時, 通過值傳遞("@")的scope 變量將不會被初始化,它們將會在指令的生命周期中另一個時間點進行初始化,如果你需要監聽這個事件,可以使用scope.$watch 方法。
好了,以上即為自定義指令需要用到基本知識描述。如果你仍然不熟悉指令,最好的方法就是動手實現幾個小例子,可以在fiddle中進行實踐:http://jsfiddle.net/powertoolsteam/Tk92U/

 

在下一篇文章中我們將一起熟悉幾個AngularJS自定義指令。

 

相關閱讀:

開放才能進步!Angular和Wijmo一起走過的日子

Angular vs React 最全面深入對比

Wijmo已率先支持Angular4 & TypeScript 2.2

 


免責聲明!

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



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