zoukankan      html  css  js  c++  java
  • Angular 新手容易碰到的坑

    Q1.<div ng-include="views/user/show.html"></div> 错在哪里?

    如果你这么写过,会发现这个位置啥也没有加载出来,那么,错在哪里呢?错在ng-include需要的是一个变量,如果你在$scope中有这样一个变量 $scope.userShowTemplateUrl = "views/users/show.html",并且把上面这句变为<div ng-include="userShowTemplateUrl"></div>就能正常工作了。或者这样写也行:<div ng-include=" 'views/user/show.html' "></div>

    原因何在?

    因为在ng-include中,是把它的参数当做变量来解释的,它会通过$eval对传入的值进行计算,然后作为模板地址去加载。

    不过,更好的方法是把这些界面片段(partical)写成指令,那样你就不用在多处重复写路径了,更重要的是,将来你可以直接在这里扩展它的交互逻辑,从界面原型平滑的演化到线上系统。

    Q2. 我的指令怎么无效?

    A2. 如果你排除了代码错误等问题,那么最可能的原因是restrict。restrict参数是用来规定你可以通过哪种方式来使用指令,而这个问题之所以容易成为坑,是因为restrict的默认值是A,也就是说,默认情况下,指令只能通过属性的形式使用,比如我写了一个指令叫做appHeader,那么默认情况下我只能用这样的形式使用它:<div app-header></div>,而<app-header></app-header>的形式则是无效的。

    所以,如果你用返回函数的形式使用指令,那么你就只能使用属性的方式调用它,比如:

    yourModule.directive('appHeader', function() {
      return function(scope, element, attrs) {
        element.text('hello');
      }
    });
    

    如果要使用元素的方式使用指令,那么你就要这样写:

    yourModule.directive('appHeader', function() {
      return {
        restrict: 'E', // 或'EA'等都可以,几种形式可以任意组合
        link: function(scope, element, attrs) {
          element.text('hello');
        }
      }
    });
    

    Q3. 修改了变量怎么界面没反应?

    A3. 首先你当然要检查有没有错误以及是否确实是scope变量,如果这些都没问题,那么多半儿是$apply导致的。对于大多数操作,$apply都会自动执行,所以你不用担心,但是如果你使用了angular之外的功能,比如直接调用了setTimeout函数、挂接了jquery的事件、使用了jquery的ajax操作等等,那么系统就没有机会帮你调用$apply,界面也就没有机会刷新了,但是你如果之后又做了其他会导致$apply的操作,你会发现以前“欠下”的那次界面刷新被正常执行了了 …… 迟到的刷新仍然是bug。

    典型代码如下:

    setTimeout(function() {
      $scope.time = new Date()
    }, 1000);
    

    这种情况下你在页面中绑定的time变量将不会被自动刷新,无论是通过{{}}表达式,还是通过ng-*属性或者其他任何形式。怎么改呢?这样:

    setTimeout(function() {
      $scope.$apply(function() {
        $scope.time = new Date();
      });
    }, 1000);
    

    不过,这不是最好的形式,最好的形式是什么呢?当然是使用angular内置的$timeout服务,它就是干这个的:

    $timeout(function() {
      $scope.time = new Date();
    });
    

    没有$apply,却正常工作,没bug,而且漂亮多了吧?不过这里别忘了你得把$timeout服务进行依赖注入,不然它是undefined。

    Q4. ng-click 写成 ng-class 导致的界面停止响应

    A4. 这是我自己犯过的一个低级错误,属于深度依赖ide导致的问题。ide的自动代码提示功能,ng-cl的第一个候选项是ng-class,如果偷懒少打了一个字,那么本来想写ng-click的代码就会写成ng-class,结果就是,无休止的重新计算ng-class中的表达式,其中的原因还没来得及看源码研究。

    如果遇到界面停止响应的问题,而且你也同样深度依赖ide,那么,从这个角度查查看吧。

    Q5. 我知道你不拜金,但别忘了$

    A5. 在angular中有一个通用的约定:angular的内部服务、方法、属性通常都会以$开头,而相应的,它也要求你自己的命名不要用$开头。比较容易忘记用$开头的主要是一些方法,特别是$apply, $watch, $on, $broardcast, $emit这些,而这些如果你写错了,在chrome中你将得到一个莫名其妙的提示 TypeError: undefined is not a function! 可恶的是,连函数名字都没有!所以,虽然我知道你不拜金,但是千万不要忘了写$!

    Q6. 注意作用域的原型继承问题!

    A6. 在Angular中,作用域是通过原型链进行继承的。而这种继承有一个问题,那就是在子类中对变量进行赋值时,不会去修改父级的。

    假设scopeA继承自scopeB,而在scopeB中定义了一个变量value: 1,这时候,读取scopeA.value可以正确取到值,但是如果赋值,就有问题了 scopeA.value = 2,这时候,scopeB.value的值是多少呢?你可能以为是2,但它是1!原因就在于原型继承时对变量的赋值不会修改原型中的值,而是直接在当前scope中创建一个同名的属性。

    这个现象导致了一个容易让新手困惑的问题:

    下面的代码工作正常:

    <label><input type="radio" ng-model="color" value="red">  Red </label><br/>
    <label><input type="radio" ng-model="color" value="green"> Green</label><br/>
    <label><input type="radio" ng-model="color" value="blue"> Blue </label><br/>
    
    {{color}}
    

    而下面的代码工作不正常,color值将不会随着选择而变化:

    <div ng-repeat="value in ['red', 'green', 'blue']">
      <label><input type="radio" ng-model="color" ng-value="value">  {{value}} </label>
    </div>
    {{color}}
    

    它的原因就在于color值定义在当前scope中,而ng-repeat创建了一个子scope,它使用原型继承的方式从父级继承下来。对color值的修改,会去修改子级的变量,而父级的同名变量不会被修改。

    要想让它正常工作,就改成这样:

    <div ng-repeat="value in ['red', 'green', 'blue']">
      <label><input type="radio" ng-model="vm.color" ng-value="value">  {{value}} </label>
    </div>
    {{vm.color}}
    

    这里,把color定义成了一个vm对象的属性,这时候,因为只需要对vm的成员进行赋值,而不存在对vm进行赋值的情况,所以赋值会正确的作用于父级scope上。这里的vm只是$scope上的一个对象,叫别的名字也可以,只是因为它的实际作用是ViewModel,所以我习惯于把它命名为vm。

    在Angular 1.2以后的版本中引入了controllerAs语法,可以一劳永逸的解决这个问题。具体的用法请参见 http://www.cnblogs.com/whitewolf/p/3493362.html

    如果使用1.2以下的版本,可以在controller的第一句加上这样的语法来模拟:

    var vm = $scope.vm = {};
    所有的$scope变量都改为赋值给vm变量就可以了,view中也要相应的引用vm变量。

    Q7. angular.module的两种写法:含义大不同

    angular.module('name', [])angular.module('name') 虽然看起来很相似,但是!它们的含义却是截然不同的!

    angular.module('name', [])是创建一个新的module,[]表示它没有依赖任何其他模块,如果已经有了一个同名模块,则会覆盖现有的。

    angular.module('name')是查找一个现有module,如果这个module不存在,则返回空值。

    如果把带方括号的形式(创建)误用为不带方括号的形式(引用),那么在它的返回值上调用controller等函数会出现空指针错误。

    而如果把引用形式误用为创建形式,则会导致难以理解的“对象不存在”错误,但是你却明明定义过那个service或者controller等对象!这种问题就是因为后面的模块定义覆盖了以前的模块定义,你定义过的那些对象都被随着以前的module而丢掉了!

    Q8. 第三方指令不起作用

    最可能的原因是你没有加入模块依赖。第三方指令通常会定义在自己的模块中,所以这个模块必须被你的app模块所依赖,其中包含的指令才能在view中使用。比如你要使用ui-select2指令,就必须在自己的模块定义中加入这个依赖:

    angular.module('app', [
      'ngCookies',
      'ngResource',
      'ngSanitize',
      'ui.select2'
    ]).....
    

    如果仍然没有解决问题,请看看控制台中有没有错误信息,以及是否存在Q2所提的情况。

    吾生有涯 而知也无涯矣
  • 相关阅读:
    树链剖分 (模板) 洛谷3384
    ST表 (模板) 洛谷3865
    IOI 2005 River (洛谷 3354)
    IOI 2005 River (洛谷 3354)
    poj1094 Sorting It All Out
    poj1094 Sorting It All Out
    spfa(模板)
    HAOI 2006 受欢迎的牛 (洛谷2341)
    HAOI 2006 受欢迎的牛 (洛谷2341)
    洛谷1850(NOIp2016) 换教室——期望dp
  • 原文地址:https://www.cnblogs.com/Sherlock09/p/7059230.html
Copyright © 2011-2022 走看看