07月02, 2016

记一次angularjs的项目总结

记录在项目中的angularjs实战。

路由

用的是ui-router,具体要掌握的几个知识点如下:

  • $stateProvider

  • $urlRouterProvider

  • ui-sref(设置链接,具体关联到什么值)

  • ui-sref-active(高亮)

  • 将$state和$stateParams绑定到根作用域

  • $state.go方法,手动触发路由

相关文章

SanitizationWhitelist

先说问题,在做项目的时候,img的src是native的协议,但angularjs不认识,然后它会加上'unsafe:'这种鬼东西。

后来查了一下文档,发现有两个东西:aHrefSanitizationWhitelistimgSrcSanitizationWhitelist,像"native的协议,javascript:;"这样的写法,都会加上unsafe,那么怎么处理呢?

$compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|javascript|native):/);

这里要注意的是provider的相关配置,都是通过angular.config来实现的。

httpProvider

通常,我们希望像ajaxSetup那样,设置一些默认的值,或者是对response的返回code做出统一的处理,那么在angular中是如何实现的?

首先我们往$httpProvider里面的interceptors新增一个或者多个拦截器,如:

$httpProvider.interceptors.push("httpInterceptor");

接着,我们需要实现自己的拦截器:

angular.module("myApp", []) 
  .factory("httpInterceptor", [ "$q", "$injector",function($q, $injector) { 
    var httpInterceptor = { 
      "responseError" : function(response) { 
        ...... 
        return $q.reject(response); 
      }, 
      "response" : function(response) { 
        ...... 
        return response; 
      }, 
      "request" : function(config) { 
        ...... 
        return config; 
      }, 
      "requestError" : function(config){ 
        ...... 
        return $q.reject(config); 
      } 
    } 
  return httpInterceptor; 
}

相关文章

Provider

深刻理解下面四种写法的区别:

var app = angular.module("myApp", []);
app.provider("greeting", ...);
app.factory("greeting", ...);
app.value("greeting", ...);  
app.const("greeting", ...);

在项目中一般用factory比较多,主要是它的写法简单,只要返回一个对象即可。

注入器($injector)

一旦拥有了$injector,可以调用get函数来获得任何一个已经被定义过的服务的实例。如:

var common =  $injector.get("common");

指令中的scope

之前在不同的指令的controller中,$scope下注册了相同的函数名,结果居然导致冲突了。

查了一下原因,才知道需要加一个scope属性,来进行隔离,即:

angular.module("offlineCourse",[])
.directive("offlineCourse",  ["commonServices", "common",  function(commonServices, common){
    return {
      controller: ["$scope", function($scope){

      }],
      scope: {},
      replace: true,
      restrict: "E",
      templateUrl: ""
    };
}]);

指令中的scope比较好玩,一般是用在父子嵌套级元素里面的。可能这对我们本身在写结构时,也要有一定的要求。它的取值: falsetrue{}

{}里面又有三种符号的前缀写法:@=&

记忆方法:

@是单向属性绑定,=是双向绑定,&是函数绑定。

这里有一篇文章,详细介绍了指令中的scope,点击查看

不过我个人的感觉,只有在父子结构,并且有明确的传值下,就像react那样,向下传递props,才用得上以上写法。在这次的项目中,并没有用到。一般更多的关注点是:指令与指令的数据共享。

指令与指令的数据共享

  • 通过$rootScope
  • 注入公共的service
  • 通过事件广播($broadcast)
  • 父子级指令(子级可以通过require父级,来得到父级scope上的方法和属性)

父子级指令需要注意的是有几个点:

a.父级指令的scope为true b.父级指令中共享的属性和方法,必须是this.xxx,之前的$scope.xxx也要保留。 c.子级在link函数中才能得到父级的对象,第四个参数,前三个参数依次为:scope、DOM对象、Attr对象

前三种方式可以查看:在多个AngularJS controller之间共享数据 - 细桶假狗屎 - 51CTO技术博客

ngDailog的拖拽处理

ngDailog本身并没有提供拖拽处理,查了一下issue,作者的回复是没有更好的理由说它一定非要支持拖拽,可以利用第三方的angular插件。

当时找了很久,没有找到一个合适的,主要是在DOM节点上加一些属性什么的,对于ngDailog很不方便。最后索性找了一个原生js,自己简单调一下,改一下。

ngDailog提供了ngDialog.opened事件,所以只要把拖拽事件放在它里面就行了,代码如下:

$rootScope.$on("ngDialog.opened", function(e, $dialog) {
        //这里就可以得到dialog具体的DOM对象了
});

须知:ngDialog.close或者ngDialog.closeAll方法是异步的,也是从一个dialog切换到另外一个dialog的时候,上面的方法一开始会得到两个dom对象,然后才会变成一个。所以在获取DOM节点的时候,要注意一下。目前我没有好的处理方式,只能获取最后一个DOM来处理。

关于代码压缩

angularjs,在写代码的时候,需要注意的是,涉及到注入的写法,都建议用[]来处理,即:

angular.module("interceptor", [])
    .factory("myInterceptor", ["$q", "$timeout", "$injector", function($q, $timeout, $injector) {
    });

因为用uglify-js,它会将$scope等这些变量压缩。当然我们也可以给压缩工具做配置,让它只是单纯的将代码放在一行:

{
    mangle: false
}

关于https

这一条其实和本文关系不大,但还是不得不提。

在把代码发上线之后,有一个文件请求似乎有问题,然后一直报错,这个问题是偶发的,在客户端打开的时候,就会出现。当刷新后,就没有这个问题了。就因为这个问题,导致晚上忙了两个小时,都没搞定。

第二天用fiddler抓包,发现文件的response被修改了,于是想到了运营商劫持网络。另外一个同事提及之前上线没问题,是因为用的https。最后找到原因了,似乎是公司网络做了一层拦截,把该网址加入白名单就正常了。

之所以把之前的https改为http,是因为有些页面是用iframe嵌套进来的,那几个页面是http,这样的话,就会有问题。

本文链接:www.my-fe.pub/post/angularjs-project-review.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。