在AngularJS中抢救指令时渲染速度问题

时间:2014-08-30 23:45:06

标签: javascript angularjs angularjs-directive

我有以下简单的基本指令:

angular.module("base", [])
  .directive("base", function() {
    return {
      restrict: "A",
      scope: true,
      controller: function($scope) {
        this.setHeader = function(header) {
          $scope.header = header;
        }
        this.setBody = function(body) {
          $scope.body = body;
        }
        this.setFooter = function(footer) {
          $scope.footer = footer;
        }
      },
      templateUrl: "base.html"
    }
  });

我通过以下方式将数据传递给此指令:

 .directive("custom", function() {
    return {
      restrict: "E",
      require: "^base",
      scope: {
        ngModel: "="
      },
      link: function($scope, $element, $attrs, baseCtrl) {
        //Do something with the data or not...
        baseCtrl.setHeader($scope.ngModel.header);
        baseCtrl.setBody($scope.ngModel.body);
        baseCtrl.setFooter($scope.ngModel.footer);
      }
    }
  });

当我创建我的custom指令列表时,我注意到custom指令不会立即呈现。我做了Plunker demonstrating这种行为。 (您将看到列表单元格在一瞬间为空,然后将出现指令)

我的设计背后的目标是重用base指令的模板,只传入显示所需的数据。在这个简单的例子中,$scope.data正是我需要传递的内容,但可能是某些规则或操作需要首先发生的情况。我没有让查询数据的控制器处理这个问题,而是希望将其传递给指令,将问题分开。

所以我的问题是

  1. 有没有办法让指令更快地渲染并避免Plunker中显示的闪烁?
  2. 这是重复使用Angular指令的最佳做法吗?

1 个答案:

答案 0 :(得分:4)

闪烁是由"base.html"文件的异步http请求引起的。由于必须从服务器加载base指令的HTML,因此将只有一小部分时间不会显示任何内容。

为了呈现data,Angular会经历这三个阶段:

  1. 从服务器获取HTML文件/模板(不会显示任何内容
  2. 编译HTML模板( DOM已更新但范围尚未链接
  3. 将范围链接到DOM /模板(显示预期数据
  4. 选项1 - 使用template属性

    只需替换直接HTML内容的templateUrl: "base.html"

    //templateUrl: "base.html"
    template: '<div class="base"><div class="header bottom-border"><h2>{{header}}</h2><div><div class="body bottom-border"><p>{{body}}</p></div><div class="footer">{{footer}}</div></div>',
    

    您会注意到这次没有任何闪烁(请查看plunker)。

    选项2 - 预加载模板文件

    Angular有一个内置模板缓存($templateCache),用于检查是否已从服务器获取任何HTML模板文件/内容。如果在加载应用程序时填充该缓存,则Angular不需要获取模板来呈现指令,它将直接从缓存中读取它。

    您可以使用Angular的$templateRequest(如果您使用的是Angular的最新测试版)或$templateCache(适用于任何版本)。 区别在于$templateRequest自动发出HTTP GET请求并将结果存储在$templateCache中。另一方面,你必须手动完成,如下所示:

    loadTemplate = function(tpl) {
      $http.get(tpl, { cache : $templateCache })
        .then(function(response) {
          $templateCache.put(tpl, html);
          return html;
        });
    };
    loadTemplate('base.html');
    

    但请注意,此方法需要您的应用具有“加载阶段”。


    关于重用指令的最佳实践,您似乎走在了正确的道路上。例如,提供任何建议都很简单......不过,请查看此Angular "Creating Custom Directives"指南中的“最佳做法”说明。

    修改

    (关于template vs templateUrl个人偏好设置)

    如果主要目标只是表现(即页面渲染速度),则template似乎是最佳选择。获取一个文件总是比获取两个文件更快...但是,随着应用程序的增长,对于良好结构的需求是必需的,并且模板文件是最佳实践之一。

    通常我遵循这个“规则”:

    1. 如果模板中只有几行HTML,那么只需使用template
    2. 即可
    3. 如果HTML模板不会随着时间的推移不断变化(即帖子结构,联系方式等等),请使用template,否则(即包含横幅/广告的模板)使用templateUrl
    4. 如果应用具有加载阶段,请使用带有缓存的templateUrl