Angular1.X

服务

1.Constant
2.Value
3.Service
4.Factory
5.Provider
除了Constant,所有类型服务背后都通过Provider实现

angular.module('lulu.app').provider('greeting', function(){
  var _name = '66';
  this.setName = function(name){
    _name = name;
  };
  this.$get = function(){
    return _name;
  }
});
angular.module('lulu.app').controller('SomeCtrl', function($scope, greeting){
  $scope.message = greeting; //值为66
});
//provider可配置
angular.module('lulu.app').config(function(greetingProvider){
  greetingProvider.setName('lulu');
});

//value
angular.module('lulu.app').value('greeting', '66');

//service
angular.module('lulu.app').service('greeting', function(){
  this.say = function(name){
    return name;
  }
});
//等价于
angular.module('lulu.app').provider('greeting', function(){
  this.$get = function(){
    var Greeting = function(){
      this.say = function(name){
        return name;
      };
    };
    //service用new的方式创建
    return new Greeting();
  };
});

//factory
angular.module('lulu.app').factory('greeting', function(){
  return 66;
});
//等价于
angular.module("lulu.app").provider('greeting', function(){
  this.$get = function(){
    var greeting = function(){
      return 66;
    }

    return greeting();
  }
});

***service和factory区别在于内部创建时一个是new一个直接返回

//constant
angular.module('lulu.app').constant('greeting', '66');

Constant时机非常早,可以在Config中使用

MVVM

View:专注显示,视图模板
ViewModel:负责给View提供显示数据,以及供View操作Model途径,$scope对象充当了这个角色
Model:领域对象,业务相关数据
Controller:负责ViewModel对象初始化

Angular启动过程

1.浏览器下载HTML/CSS/Javascript
2.浏览器开始构建DOM
3.Jquery初始化
4.Angular初始化:创建各种模块,在模块中注册各种Angular对象
5.Jquery启动
6.AngularI启动,查找第一个带有ng-app的节点
7.加载子模块,关联DOM和模块,使DOM变活(展示数据,响应事件)
8.启动子模块,执行run回调
9.渲染页面
10.数据绑定与digest循环

依赖注入DI

只要指出我需要哪些对象,让后就会有人(框架)把这个对象给我

Javascript中实现DI
函数对象的toString(),返回函数源码,解析源码参数

Angular中的DI
所有主要编程元素都要通过某种方式注册
注册表Module,Angular跨Controller共享数据或通讯,可以创建Service/Value/Constant分别注入,共享同一对象
provider通过$get函数注入,provider('test', function(/只能注入constant, provider/))
循环依赖不能使用依赖注入,可以在代码内部调用
var http = $injector.get('$http');

Digest

Angular将双向绑定转换成一堆watch,递归检查watch表达式结果是否改变,等到Model值不再变化,不会触发watcher函数,一个完整的digest循环结束
Angular拓展了浏览器事件模型,建立了自己上下文,ngClick, ngChange会将浏览器事件转化为$scope的响应函数,响应函数中改变Model,触发脏检查机制,并不存在定时的脏检查

遍历一遍所有watcher函数称为一轮脏检查,执行完一轮,如果任何一个watcher监听值改变,再进行一轮脏检查,直到所有watchers函数都报告值不变了,$digest循环结束,才能把变化更新到DOM

何时进入脏检查?
每一个进入Angular上下文环境的事件,都会执行一次$digest

$watch函数返回一个反注册函数
$scope.$apply(function(){}); //手动触发digest循环

$rootScopt是所有$scope基础

指令生命周期

Inject, Compile, Controller加载, pre-link, post-link

angular.module('lulu.app').directive('test', function(){
  console.log('Inject'); //只发生一次

  return {
    restrict:'EA',
    transclude:true,
    replace:true,
    template:'
{{count}}
', scope:{ count:'=' }, //每个指令实例化时执行一次,传入elm还未被link,无法访问$scope compile:function(elm, iAttrs){ console.log('compile' + iAttrs.count); //controll初始化$scope后,进入正式解析过程,对每个实例只执行一次 return { //从父节点到子节点触发,子节点DOM不稳定,不适合在其上加DOM监听 pre:function(scope, elm, iAttrs){ console.log('pre-link' + iAttrs.count + ' scope' + scope.count); }, //从子节点到父节点触发 post:function(scope, elm, iAttrs){ console.log('post-link' + iAttrs.count + ' scope' + scope.count); } }; }, //初始化$scope controller:function($scope){ console.log('controller'); } }; });

$observe监听DOM中属性值变化
$watch监听scope属性变化

指令scope绑定策略
@绑定{{}},单向绑定,返回String
=绑定一个对象,双向绑定,返回Object
&绑定一个函数

指令scope作用域
false:直接使用父级scope
true:继承父级scope,创建后copy父scope,与父级无关
{}:创建一个新的隔离scope

controller as vm

好处:
1.$scope注入不再是必须的(除非用到$watch, $emit, $on等)
2.避免this指针坑
3.避免原型链继承对于值类型的坑(视图模板所有字段都限制于vm别名应用的属性,会导致整个页面刷新)

{{vm.name}}
(function(){
  angular.module('lulu.app')
  .controller('HomeCtrl', HomeCtrl);
  
  function HomeCtrl(){
    var vm = this;
    vm.name = 66;
  };
});

性能

1.移除不必要的$watch
2.::语法,实现one-time绑定
3.滚屏加载数据,分部加载数据
4.$compileProvider.debugInfoEnabled(true);
5.慎用filter,$digest中,filter至少执行2次,应避免filter执行耗时操作,或在controller中预先处理完数据在视图中直接绑定
6.ng-repeat添加track by可以避免$scope.tasks = data;移除所有DOM后重新渲染,track by可以对应原DOM进行更新
angular不会大范围更新DOM,每次更新区域小,超过2000个watcher需要好好考虑优化

拦截器(AOP机制)

实现Ajax请求拦截切入

防闪烁

{{}}替换为ng-bind
ngCloak通过样式切换实现隐藏显示

父子$scope嵌套

默认使用原型链继承来至父级的$scope

{{greeting}}
{{greeting}}
//ParentCtrl
$scope.greeting = "66";

导致的问题:
1.开始全部显示66
2.改变父input值,全部同步数据
3.改变子input值,子组件同步数据,父组件不能同步,再改变父input,子组件也不会同步数据
原因:
子组件开始自己没有greeting,会向上查找使用父的greeting属性
当子组件input值变更,子组件创建自己的greeting属性,后就与父级greeting属性隔离
使用controller as vm语法绑定vm.greeting可避免

路由

(function(){
  angular.module('lulu.routes')
  .config(routesConfig);

  function routesConfig($stateProvide, $urlRouterProvider){
    $stateProvide
      .state('book', {
        cache:true,
        url:'/book',
        templateUrl:'templates/product/book.html',
        controller: 'BookCtrl',
        controllerAs: 'vm',
        resolve:{
          //返回一个promise,如promise状态reject,会挡住路由
          //如不是promise, 对象会被注入到controller
          loggedIn:function(mkAuth){
            return mkAuth.checkLoggedIn();
          }
        }
      })
  };
});

ng-show/ng-hide/ng-if

ng-show/ng-hide通过css的display实现隐藏显示,ng-if通过移除添加DOM实现

$rootScope和$scope

$rootScope是页面所有$scope父级
1.angular解析ng-app创建$rootScope
2.解析{{}}为变量
3.解析ng-controller创建$scope

{{}}原理

使用$interpolation服务查看文本节点是否有{{}}(插补标记),有则注册watches,成为digest检查的一部分

$timeout.cancel();

ng-repeat迭代

track by $index解决绑定数据相同(唯一表示数据和DOM关系)

页面{{}},ng-click中可以用js原生方法么?

不能,因为$scope上下文不存在那些原生方法,如用as vm模式可以吧?

SPA缺点

1.SEO,可通过Prerender解决部分
2.前进,后退等要程序管理

SPA SEO解决方案:
1.接入prerender.io等预渲染服务
2.腾出一台服务器搭建phantomjs搞预渲染
3.将爬虫请求引导到后台定时生成或抓取的静态HTML页
4.SSR

项目

微信登录授权


微信登录
function freshConfig() {
    var url = $location.absUrl();
    url = url.split('#')[0];
    //传入当前url
    weixin.jssdkConfig({url: url}).then(function (data) {
        if (data.code == 0) {
          //配置wx
          wx.config({
            debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
            appId: mkGlobalVal.weixin_appid, // 必填,公众号的唯一标识
            timestamp: parseInt(data.result.timestamp), // 必填,生成签名的时间戳
            nonceStr: data.result.noncestr, // 必填,生成签名的随机串
            signature: data.result.signature,// 必填,签名,见附录1
            jsApiList: ['onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
              });
            }
          });
};

function onShare(share) {
    //分享到朋友圈
    wx.onMenuShareTimeline(share);
    //分享给朋友
    wx.onMenuShareAppMessage(share);
    //分享到QQ
    wx.onMenuShareQQ(share);
    //分享到腾讯微博
    wx.onMenuShareWeibo(share);
    //分享到QQ空间
    wx.onMenuShareQZone(share);
}

//微信支付
if ($scope.mkTools.agentIsWeichat) {
    orderInfo = {
        "openid": $scope.currentUser.authData.weixin.openid,
        "no": data.no,
        "total_fee": data.total_fee,
        "body": data.product_snapshot.title
      };
          mkPayTools.weixinPay(orderInfo).then(angular.noop, error);
}
//创建订单成功后,呼出微信支付界面
function weixinBridge(data, defer) {
        function onBridgeReady() {
          WeixinJSBridge.invoke('getBrandWCPayRequest', data, function (res) {
            //支付成功
            if (res.err_msg == "get_brand_wcpay_request:ok") {
              defer.resolve();
              window.location.href = "/#/payresult";
            }
            else {
              defer.reject();
            }
          });
        };

        if (typeof WeixinJSBridge == "undefined") {
          if (document.addEventListener) {
            document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
          } else if (document.attachEvent) {
            document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
            document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
          }
        }
        else {
          onBridgeReady();
        }
      };

      return defer.promise;
    };

你可能感兴趣的:(Angular1.X)