AngularJS整理(1.0.0)

恰丶如其分發表於2019-02-27
AngularJS資料雙向繫結實現原理
  • 每一個雙向繫結的元素都有一個watcher
  • 在某些事件發生時,呼叫digest髒資料檢測。事件有:表單內容變化,Ajax請求響應,點選按鈕執行函式等
  • 髒資料檢測會檢測rootscope下所有被watcher的元素
  • $digest函式觸發髒資料監測

Angular生命週期

應用啟動後,進行編譯和連結,作用域同HTML繫結。瀏覽器載入html,渲染dom樹----廣播一個事件----ng監聽dom完成事件,查詢ng-app元素----ng以當前dom為起點開始遞迴查詢所有子元素,符合應用程式定義好的指令規則。

編譯階段: angularjs遍歷整個html文件,並根據指令定義來處理頁面上宣告的指令。指令也可能在套用其它指令。有機會在指令的模板函式返回前,對編譯後的DOM樹進行修改。

連結階段:連結函式將模板和作用域連結起來;設定事件監聽,監視資料變化等等。如果定義了編譯函式,會返回連結函式,如果都定義了,編譯函式會過載連結函式。

angular.module('moduleName',[])
    .directive('name',['$http',function($http){
        return {
            restrict: 'A',
            scope:{},
            template: '<div ng-transclude>當前內容會被替換</div>'
            transclude: true,
            compile: function(element,attrs,transcludeFn){
                //進行編譯後的操作
                return {
                    pre: function(scope,element,attrs,controller){
                        //子元素被連結之前
                    },
                    post: function(scope,element,attrs,controller){
                        //子元素被連結之後
                    }
                }
            },
            link: function(scope,element){
                //定義了compile函式,不會執行link函式
            },
            controller: function($scope,$transclude){
                //controller和link都定義了,controller會先執行,在執行link函式
                //指令的控制器和link函式可以進行互換。控制器主要是用來提供可在指令間複用的行為,但連結函式只能在當前內部指令中定義行為,且無法在指令間複用.link函式可以將指令互相隔離開來,而controller則定義可複用的行為。
            }
        }
    }])
複製程式碼

程式啟動
//手動啟動
var module = angular.module("myApp",[]);
module.controller("MyCtrl",['$scope',function($scope){
    //code
}])

angular.element(document).ready(function(){
    angualr.bootstrap(document,['module'])
})

//自動啟動,找到ng-app標籤啟動
var module = angular.module('myApp',[]);
<body ng-app="myApp">

複製程式碼

依賴注入
  • 原理:假設函式的引數名就是依賴服務的名字,在依賴對映中,去查詢具體的依賴項服務
//1.陣列注入(注意依賴項的順序)
myApp.controller('myCtrl',['$scope','$http',function($scope,$http){
    
}])
//2.顯示$inject
myApp.controller('myCtrl',myCtrl);
function myCtrl($scope,$http){
    
} 
myCtrl.$inject = ['$scope','$http']
複製程式碼

controller之間通訊
  • event事件傳播方式
//父傳子
$rootScope.$broadcast(name,params)
//子傳父
$scope.$emit(eventname,params)

$scope.$on(name,function(event,data){})
複製程式碼
  • 建立service
    • 建立專用的事件Service,按照業務邏輯切分,資料儲存在Service中
  • $rootScope方式
  • 本地儲存localstore等等

  • ng-repeat迭代時遇見相同值,track by $index
  • 通過使用$ sce.trustAsHtml(),該方法將值轉換為特權所接受並能安全地使用“ng-bind-html”

ng-if/ng-show/hide區分
  • ng-if生成新的作用域
  • ng-if控制dom的增刪來控制節點,ng-show初始化時就建立了,用display:block/none來控制

產生的一個小問題:在 ng-if 中用基本變數繫結 ng-model,並在外層 div 中把此 model 繫結給另一個顯示區域,內層改變時,外層不會同步改變,因為此時已經是兩個變數了。避免這類問題出現的辦法是,始終將頁面中的元素繫結到物件的屬性(data.x)而不是直接繫結到基本變數(x)上。

<p>{{name}}</p>
<div ng-if="true">
    <input type="text" ng-model="name">
</div>
複製程式碼

效能優化問題
  • 減少監控項(不會變化的資料採用單向繫結)
    • 單次繫結{{::item}}
  • 主動設定索引
  • 資料變更檢測與繫結的方式
  • 索引的效能
  • 資料的大小
  • 資料的結構

建立services

services在需要的時候被建立,只在應用生命週期結束的時候才會被清除;而controllers在不需要的時候就會被銷燬

  • factory()
    • factory()定義的服務不能注入到config()中
angular.module('myapp.Services').factory('User',function($http){
    var def = {
        //code
    }
    return def;
})


angular.module('myApp').controller('MainCtrl',function($scope,User){
    //code
})


複製程式碼
  • service()
angualr.module('myApp.services').service('User',function($http){
  var self = this; // Save reference
  var backendUrl = "http://localhost:3000";

  this.user = {};

  this.setName = function(newName) {
    self.user['name'] = newName;
  }
  this.setEmail = function(newEmail) {
    self.user['email'] = newEmail;
  },
  this.save = function() {
    return $http.post(backendUrl + '/users', {
      user: this.user
    });
  }
  
})
複製程式碼
  • provider()
    • 唯一一個可以使用.config()方法配置建立service的方法
    angular.module('myApp.services').provider('User',function(){
        this.backendUrl = "http://localhost:3000";
        this.setBackendUrl = function(newUrl) {
          if (url) this.backendUrl = newUrl;
        }
      
        this.$get = function($http) { // injectables go here
          var self = this;
          var service = {
            user: {},
            setName: function(newName) {
              service.user['name'] = newName;
            },
            setEmail: function(newEmail) {
              service.user['email'] = newEmail;
            },
            save: function() {
              return $http.post(self.backendUrl + '/users', {
                user: service.user
              })
            }
          };
          return service;
        }
    })
    複製程式碼
    -使用provider()
angular.module('myApp').config(function(UserProvider) {
    // config()裡只能注入provider,注意名稱是服務名稱+Provider
    UserProvider.setBackendUrl("http://myApiBackend.com/api");
})


angular.module('myApp').controller('MainCtrl', function($scope, User) {
    // controller裡面注入服務,只能呼叫provider的get方法裡定義的內容
    $scope.saveUser = User.save;
});
複製程式碼
過濾器filter
  • 在模板中使用
{{expression|filter1|filter2|filter3|...}}//串起來使用
{{expression|filter:argument1:argement2:...}}//接收引數
<span ng-repeat="a in array | filter">//在指令中使用
複製程式碼
  • 在controller和service中使用
//方式1
app.controller('testC', function($scope, currencyFilter){
    $scope.num = currencyFilter(123534);  
}

//方式2
app.controller('testC', function($scope, $filter){
    $scope.num = $filter('currency')(123534);
    $scope.date = $filter('date')(new Date());  
}
複製程式碼
指令

指令詳解

  • restrict[string]
    • A代表屬性、E代表元素、C代表類、M代表註釋
  • template/templateUrl [string/function]
  • priority[number]
    • 自定義指令的優先順序,當一個DOM元素上有一個以上的指令的時候,就需要比較指令的優先順序。
  • terminal[boplean]
    • 是否停止當前元素上比本指令優先順序低的指令
  • replace[boolean]
  • link[function]
    • scope-沒定義當前指令scope屬性時候,代表父controller的scope
    • element-jQLite包裝的DOM元素
    • attrs-包含該指令所在元素的屬性的標椎化引數物件
  • scope[boolean/object]
    • 預設是false,繼承父controller的scope
    • true時,建立一個繼承父scope的scope
    • {},建立一個隔離的scope,不會繼承父scope
      • @單項繫結
      • =雙向繫結
      • &呼叫父scope裡的方法
  • transclude[boolean]
    • 規定指令是否可以包含任意內容
  • compile[function]
    • 寫了compile函式,link函式不會執行
    • compile可以rueturn prelink和postlink
angular.module('moduleName',[])
    .directive('name',['$http',function($http){
        return {
            restrict: 'A',
            scope:{},
            link: function(scope,element){
                
            }
        }
    }])
複製程式碼

相關文章