zoukankan      html  css  js  c++  java
  • AngularJS 的一些坑

    UI的闪烁

    Angular的自动数据绑定功能是亮点,然而,他的另一面是:在Angular初始化之前,页面中可能会给用户呈现出没有解析的表达式。当DOM准备就绪,Angular计算并替换相应的值。这样就会导致出现一个丑陋的闪烁效果。

    上述情形就是在Angular教程中渲染示例代码的样子:

    <body ng-controller="PhoneListCtrl">
      <ul>
        <li ng-repeat="phone in phones">
          {{ phone.name }}
          <p>{{ phone.snippet }}</p>
        </li>
      </ul>
    </body>

    如果你做的是SPA(Single Page Application),这个问题只会在第一次加载页面的时候出现,幸运的是,可以很容易杜绝这种情形发生: 放弃{{ }}表达式,改用ng-bind指令

    <body ng-controller="PhoneListCtrl">
      <ul>
        <li ng-repeat="phone in phones">
          <span ng-bind="phone.name"></span>
          <p ng-bind="phone.snippet">Optional: visually pleasing placeholder</p>
        </li>
      </ul>
    </body>

    你需要一个tag来包含这个指令,所以我添加了一个<span>给phone name.

    那么初始化的时候会发生什么呢,这个tag里的值会显示(但是你可以选择设置空值).然后,当Angular初始化并用表达式结果替换tag内部值,注意你不需要在ng-bind内部添加大括号。更简洁了!如果你需要符合表达式,那就用ng-bind-template吧,

    如果用这个指令,为了区分字符串字面量和表达式,你需要使用大括号

    另外一种方法就是完全隐藏元素,甚至可以隐藏整个应用,直到Angular就绪

    Angular为此还提供了ng-cloak指令,工作原理就是在初始化阶段inject了css规则,或者你可以包含这个css 隐藏规则到你自己的stylesheet。Angular就绪后就会移除这个cloak样式,让我们的应用(或者元素)立刻渲染。

    Angular并不依赖jQuery。事实上,Angular源码里包含了一个内嵌的轻量级的jquery:jqLite. 当Angular检测到你的页面里有jQuery出现,他就会用这个jQuery而不再用jqLite,直接证据就是Angular里的元素抽象层。比如,在directive中访问你要应用到的元素。

    angular.module('jqdependency', [])
      .directive('failswithoutjquery', function() {
        return {
          restrict : 'A',
          link : function(scope, element, attrs) {
                   element.hide(4000)
                 }
        }
    });

    但是这个元素jqLite还是jQuery元素呢?取决于,手册上这么写的:

    Angular中所有的元素引用都会被jQuery或者jqLite包装;他们永远不是纯DOM引用 

    所以Angular如果没有检测到jQuery,那么就会使用jqLite元素,hide()方法值能用于jQuery元素,所以说这个示例代码只能当检测到jQuery时才可以使用。如果你(不小心)修改了AngularJS和jQuery的出现顺序,这个代码就会失效!虽说没事挪脚本的顺序的事情不经常发生,但是在我开始模块化代码的时候确实给我造成了困扰。尤其是当你开始使用模块加载器(比如 RequireJS), 我的解决办法是在配置里显示的声明Angular确实依赖jQuery

    另外一种方法就是你不要通过Angular元素的包装来调用jQuery特定的方法,而是使用$(element).hide(4000)来表明自己的意图。这样依赖,即使修改了script加载顺序也没事。

    压缩

    特别需要注意的是Angular应用压缩问题。否则错误信息比如 ‘Unknown provider:aProvider  <- a’ 会让你摸不到头脑。跟其他很多东西一样,这个错误在官方文档里也是无从查起的。简而言之,Angular依赖参数名来进行依赖注入。压缩器压根意识不到这个这跟Angular里普通的参数名有啥不同,尽可能的把脚本变短是他们职责。咋办?用“友好压缩法”来进行方法注入。看这里:

    module.service('myservice', function($http, $q) {
    // This breaks when minified
    });

    to this:

    module.service('myservice', [ '$http', '$q', function($http, $q) {
    // Using the array syntax to declare dependencies works with minification<b>!</b>
    }]);

    这个数组语法很好的解决了这个问题。我的建议是从现在开始照这个方法写,如果你决定压缩JavaScript,这个方法可以让你少走很多弯路。好像是一个automatic rewriter机制,我也不太清楚这里面是怎么工作的。

    最终一点建议:如果你想用数组语法复写你的functions,在所有Angular依赖注入的地方应用之。包括directives,还有directive里的controllers。别忘了逗号(经验之谈)

    // the directive itself needs array injection syntax:
    module.directive('directive-with-controller', ['myservice', function(myservice) {
        return {
          controller: ['$timeout', function($timeout) {
            //  but this controller needs array injection syntax, too! 
          }],
          link : function(scope, element, attrs, ctrl) {
     
          }
        }
    }]);

    注意:link function不需要数组语法,因为他并没有真正的注入。这是被Angular直接调用的函数。Directive级别的依赖注入在link function里也是使用的。

     Directive永远不会‘完成’

    在directive中,一个令人掉头发的事就是directive已经‘完成’但你永远不会知道。当把jQuery插件整合到directive里时,这个通知尤为重要。假设你想用ng-repeat把动态数据以jQuery datatable的形式显示出来。当所有的数据在页面中加载完成后,你只需要调用$(‘.mytable).dataTable()就可以了。 但是,臣妾做不到啊!

    为啥呢?Angular的数据绑定是通过持续的digest循环实现的。基于此,Angular框架里根本没有一个时间是‘休息’的。 一个解决方法就是将jQuery dataTable的调用放在当前digest循环外,用timeout方法就可以做到。

    angular.module('table',[]).directive('mytable', ['$timeout', function($timeout) {
        return {
          restrict : 'E',
          template: '<table class="mytable">' +
                       '<thead><tr><th>counting</th></tr></thead>' +
                       '<tr ng-repeat="data in datas"><td></td></tr>' +
                    '</table>',
          link : function(scope, element, attrs, ctrl) {
             scope.datas = ["one", "two", "three"]
             // Doesn't work, shows an empty table:
             // $('.mytable', element).dataTable()  
             // But this does:
             $timeout(function() {
               $('.mytable', element).dataTable();
             }, 0)
          }
        }
    }]);

    在我们的代码里甚至遇到过需要双重嵌套$timeout。还有更疯狂的就是添加<script>tag 到模板中,这个脚本里回调Angular的scope.$apply()方法。我只想说,这很不完美。基于Angular的实现机理,这很难改变。

  • 相关阅读:
    linux之dup和dup2函数解析
    UNIX标准及实现
    UNIX基础知识
    HTML5学习笔记----html5与传统html区别
    c#设计模式-简单工厂
    c#设计模式-工厂模式
    MVC模式与三层架构的区别
    C# params传递多个参数
    SFC20 功能例子 注解
    工业以太网:十个核心基础概念
  • 原文地址:https://www.cnblogs.com/axl234/p/5242191.html
Copyright © 2011-2022 走看看