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:'<div>{{count}}</div>',
    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别名应用的属性,会导致整个页面刷新)

<div>{{vm.name}}</div>
(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

<div ng-controller='ParentCtrl'>
  {{greeting}}
  <input type="text" ng-model="greet"/>
  <div ng-controller='ChildCtrl'>
    {{greeting}}
    <input type="text" ng-model="greet"/>
  </div>
</div>
//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

项目

微信登录授权

<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<a href="https://open.weixin.qq.com/connect/oauth2/authorize?appid={3}&redirect_uri={2}&response_type=code&scope=snsapi_userinfo&state={0}#wechat_redirect">微信登录</a>
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;
    };
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容

  • Angular面试题 一、ng-show/ng-hide与ng-if的区别? 第一点区别是,ng-if在后面表达式...
    w_zhuan阅读 5,527评论 0 26
  • AngularJS是什么?AngularJs(后面就简称ng了)是一个用于设计动态web应用的结构框架。首先,它是...
    200813阅读 1,606评论 0 3
  • 1、angularjs的几大特性是什么? 双向数据绑定、依赖注入、模板、指令、MVC/MVVM 2、列举几种常见的...
    2e9a10d418ab阅读 1,271评论 0 10
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,656评论 18 139
  • 《乖,摸摸头》-大冰 其实,刚开始看到这本书时我是拒绝读的,因为我知道,这会是一本鸡汤书。但是,我又觉得,还没读一...
    千山万水阅读 562评论 4 6