Angular ng-if和ng-show组合

时间:2015-01-24 18:20:49

标签: angularjs angularjs-directive

想象一下可能在网页上呈现的一些繁重的内容,例如图表。 Angular提供2个选项来切换所述内容的可见性。

无论表达式如何,

ng-show 都会呈现内容,并在事后简单地“隐藏”它。这并不理想,因为用户可能永远不会在会话期间“打开”内容,因此渲染它是一种浪费。

ng-if 在这方面更好。如果表达式为false,使用它代替ng-show将防止重型内容首先呈现。然而,它的优势也是它的弱点,因为如果用户隐藏图表然后再次显示它,则每次都会从头开始呈现内容。

如何制定充分利用这两个方面的指令?这意味着它就像ng-if直到第一次呈现内容一样,然后切换到像ng-show一样的工作,以防止每次都重新呈现它。

4 个答案:

答案 0 :(得分:20)

+1对丹尼斯的回答,但为了完整起见,甚至可以通过将逻辑保持在视图中而不用"污染"来进一步简化它。控制器:

<button ng-click="show = !show">toggle</button>
<div ng-if="once = once || show" ng-show="show">Heavy content</div>

plunker

编辑:通过一次性绑定可以进一步改进(和简化)以上版本,以减少once上不必要的$ watch - 这只适用于Angular 1.3+:

<div ng-if="::show || undefined" ng-show="show">Heavy content</div>

需要undefined以确保观看的值在变为true之前不会"stabilize"。一旦稳定,它也会失去$ watch,因此不会受到show的任何进一步更改的影响。

答案 1 :(得分:9)

您可以将ngIfngShow放在一起使其工作,其中每个控件都由不同的变量控制。 ngIf将被设置为true一次,并且永远不会再设置为false,而ngShow将会根据用户的需要进行切换。

看看这个fiddle

答案 2 :(得分:5)

@ new-dev的回答启发了我自己的组合想法,使用切换按钮快速获得非常重的组件。

我最初的问题是我的页面包含~20个组件,每个组件需要大约1秒钟才能加载。每个人都被一个按钮切换。

如果使用普通ng - 如果我将在切换按钮后立即加载页面并延迟1秒。

如果使用普通的ng-show我会立即切换按钮,但是20秒的页面加载延迟......

所以,现在我也将它们与ng-mouseenter对照结合起来。像这样。

<div ng-mouseenter="create=true">
    <button ng-click="showAll = !showAll"></button>
    <!--lightweight content-->
    <div ng-show="showAll">
        <div ng-if="create">
            <!--Heavy content-->
        </div>
    </div>
</div>

这让我在Chrome和IE中都表现出色。用户在进入组件后实际单击按钮所花费的时间用于创建DOM。然后,DOM节点会快速显示一次(如果)点击到达。

我也从未将ng-if表达式再次设置为false。如果用户保持切换该部分,则保持DOM缓存。

<强>更新: 我在同一个div上没有ng-if和ng-show的原因是在IE中它引起了闪烁。当mouseenter事件到达时,它将显示内容然后隐藏它。在Chrome中,可以将它放在同一个div上。

答案 3 :(得分:0)

您可能对Alan Colver的自定义指令ng-lazy-show感兴趣。它允许合并ng-ifng-show

<div ng-lazy-show="showFilters" lendio-business-filters></div>

代码很小,很容易添加到您的项目中:

var ngLazyShowDirective = ['$animate', function ($animate) {

  return {
    multiElement: true,
    transclude: 'element',
    priority: 600,
    terminal: true,
    restrict: 'A',
    link: function ($scope, $element, $attr, $ctrl, $transclude) {
      var loaded;
      $scope.$watch($attr.ngLazyShow, function ngLazyShowWatchAction(value) {
        if (loaded) {
          $animate[value ? 'removeClass' : 'addClass']($element, 'ng-hide');
        }
        else if (value) {
          loaded = true;
          $transclude(function (clone) {
            clone[clone.length++] = document.createComment(' end ngLazyShow: ' + $attr.ngLazyShow + ' ');
            $animate.enter(clone, $element.parent(), $element);
            $element = clone;
          });
        }
      });
    }
  };

}];

angular.module('yourModule').directive('ngLazyShow', ngLazyShowDirective);