AngularJS整理(1.0.0)

838 阅读2分钟
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){
                
            }
        }
    }])