这学期基本都是在学习和使用 Angular ,这篇文章主要是想介绍几个 Angular 需要注意或者了解的地方。

Angular作用域

​ 也许你知道 ng-if 和 ng-show 的区别是一个只有条件满足的时候才会创建 DOM ,一个是只有在条件满足的时候才会显示 DOM 也就是一开始也会跟着创建。但是你可能不知道, ng-if 会产生新的作用域, ng-repeat 和 ng-switch 和 ng-include 也是如此。这时候内部如果使用外部的变量,第一次的时候会正常显示,因为 Angular 的继承是原型链继承,如果子类没有这个属性就会去尝试继承父类的属性, Angular 会拿父类的属性来创建新的属于这个子类的属性,而这个属性将不再和外层的父类的属性挂钩,如果不注意很可能就会在这里踩坑。

读子类的属性时,子类有这个属性(hasOwnProperty)的时候则读子类自己的,子类没有的时候读父类的,不管子类有没有这个属性,在子类上都不会有新属性被创建。

写子类的属性时,如果子类有这个属性(hasOwnProperty)则写子类的,子类没有的话就会在子类上新建一个同名的新属性,而父类继承过来的属性被隐藏。

​ 关于原型链继承这个可以参考此处JavaScript Prototypal Inheritance,或者[译文] 深入浅出 AngularJS 作用域

​ 使用上述的 ng-if , ng-repeat , ng-switch , ng-include 都会自己创建一级作用域,这点一定要注意。如果想要和父类的属性挂钩,可以使用 $parent 。

​ 但是,还没玩,也许这些你都知道。但是除了这些指令之外, textarea 也会自己创建一级作用域。所以你可能会发现你在 textarea 写的内容获取不到,但是却发现 textarea 总能取到第一次分配的初值。比如

1
<textarea ng-model="content", name="content" class="form-control" row="3"></textarea>

​ 我们在控制器里面定义

1
$scope.content = "测试"

​ 然后我们就会看到 textarea 的初值为”测试”,但是当我们更改其中的内容之后, $scope.content 却一直保持不变。

​ 同样,我们可以使用 $parent 的方式来解决这个问题。

1
<textarea ng-model="$parent.content", name="content" class="form-control" row="3"></textarea>

​ 那如果不想使用 $parent 的话,可以给 content 分配一个类名,比如

1
<textarea ng-model="comment.content", name="content" class="form-control" row="3"></textarea>

​ 这样我们就可以通过 $scope.comment.content 来取值。

Angular track by

​ 在使用 Angular 的 ng-repeat 迭代数组时,有时候会出现 Duplicates in a repeater are not allowed 的提示。

​ track by 是用来建立 $watchCollection 和 DOM 之间的联系。建议自己加上 track by 后面带的值可以自己写,但要确保每个 ngRepeat 的值唯一,比如可以写 track by $index 。

​ 之所以要这么做,是因为,如果不使用 track by ,那么每个 ng-repeat 都会添加一个 $$hashkey 来对的 DOM 进行跟踪,这样会导致不能存在相同的 DOM ,使用 track by 的意义是避免不必要的渲染。

​ 官网API有进行详细的说明,不过我看了之后还是感觉不太明白,等我了解清楚了再来补充下。AngularJS: API: ngRepeat

If you are working with objects that have an identifier property, you should track by the identifier instead of the whole object. Should you reload your data later, ngRepeat will not have to rebuild the DOM elements for items it has already rendered, even if the JavaScript objects in the collection have been substituted for new ones. For large collections, this significantly improves rendering performance. If you don’t have a unique identifier, track by $index can also provide a performance boost.

Angular拦截器

​ Angular 拦截器是 Angular 的一个强大功能,不过暂时没有怎么去研究,简单说下我的一些使用。

  • 判断请求是否成功

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $httpProvider.defaults.transformResponse.push((response) => {
    if(typeof(response.data) != undefined && response.status == 'success') {
    response = response.data;
    return response;
    }
    if(response.status == 'error') {
    console.log("Err: " + response.message);
    return;
    }
    return response;
    });

    应该都能看懂,就不过多解释了。需要说明你的是,我们只需要一次配置,即可在整个项目中适用,特别方便。

  • timestampMarker

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    app.factory('timestampMarker', [() => {
    let timestampMarker = {
    request: (config) = > {
    config.requestTimestamp = new Date().getTime();
    return config;
    },
    response: (response) = > {
    response.config.responseTimestamp = new Date().getTime();
    return response;
    }
    };
    }]);

    这是给每个请求加上时间戳来防止浏览器缓存。

  • tokenInjector

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    app.factory('tokenInjector', ['$injector', '$q', ($injector, $q) => {
    let tokenInjector = {
    request: (config) => {
    let url = host + '/auth_verify';
    let deferred = $q.defer();
    let http = $injector.get('$http');
    if(config.url === url) {
    return config;
    }
    if(sessionStorage.verify === 'true') {
    let timestamp = new Date().getTime() / 1000;
    if(timestamp - sessionStorage.createdtime >= 7000) {
    sessionStorage.verify = false;
    }
    config.headers['token'] = sessionStorage.token;
    config.headers['userid'] = sessionStorage.user_id;
    deferred.resolve(config);
    }
    }
    }
    }])

    ​上面是我从我的项目中截取的代码,作用是每次请求时,如果已经验证过,判断 token 创建时间和当前时间以判断 token 是否过期,如未过期,将 token 和 userid 加到请求的 headers 中。如果没有验证或者已经超时,则要去获取新的 token ,这里没有把代码写上。

​通过这三个例子,我想已经很明显的展示了 Angular 拦截器的强大之处。一次使用,终身受益,爽。