ng-if和ng-show/ng-hide有什么区别?

432

我想了解ng-ifng-show/ng-hide之间的区别,但它们对我来说看起来一样。

选择使用其中之一时,我应该注意哪些差异?


12个回答

526

ngIf

ngIf指令会根据表达式来移除或重新创建DOM树中的某个部分。如果赋值给ngIf的表达式返回false,则该元素从DOM中移除,否则该元素的克隆将重新插入到DOM中。

<!-- when $scope.myValue is truthy (element is restored) -->
<div ng-if="1"></div>

<!-- when $scope.myValue is falsy (element is removed) -->
<div ng-if="0"></div>

当使用ngIf移除一个元素时,它的作用域会被销毁,并在元素恢复时创建一个新的作用域。 ngIf中创建的作用域通过原型继承从其父级作用域继承。

如果在ngIf内部使用ngModel来绑定到父级作用域中定义的JavaScript原始值,那么在子级作用域中对变量所做的任何修改都不会影响父级作用域中的值,例如:

<input type="text" ng-model="data">
<div ng-if="true">
    <input type="text" ng-model="data">
</div>        

为了解决这种情况并从子级范围内更新父级范围中的模型,请使用对象:

<input type="text" ng-model="data.input">
<div ng-if="true">
    <input type="text" ng-model="data.input">
</div>

或者,使用$parent变量引用父作用域对象:

<input type="text" ng-model="data">
<div ng-if="true">
    <input type="text" ng-model="$parent.data">
</div>

ngShow

ngShow指令根据提供给ngShow属性的表达式,决定是否显示给定的HTML元素。通过添加或移除元素上的ng-hide CSS类来显示或隐藏该元素。.ng-hide CSS类在AngularJS中预定义,并将显示样式设置为none(使用!important标志)。

<!-- when $scope.myValue is truthy (element is visible) -->
<div ng-show="1"></div>

<!-- when $scope.myValue is falsy (element is hidden) -->
<div ng-show="0" class="ng-hide"></div>

ngShow表达式的结果为false时,将向class属性添加ng-hideCSS类,导致元素变为隐藏状态。当为true时,将从元素中删除ng-hide CSS类,使元素不再处于隐藏状态。


31
提示:通过使用 ng-if 移除 HTML 元素本身,由 ng-model 添加的模型将不再存在。 - e382df99a7950919789725ceeec126
3
我已经成功地使用了ng-if替换了页面上本来会有大量dom的ng-show / ng-hide。这似乎让页面_感觉_更快,但这并不是科学分析。 - Ed Spencer
7
@mcpDESIGNS 的意思是,ngIf 指令会创建一个新的作用域。因此,在上面的示例中,嵌套的 ngModel 将创建一个新的 data 模型,即使具有相同名称的模型存在于父作用域中。但是,当您使用点表示法时,您让 JavaScript 查找作用域的原型链。因此,如果在当前作用域中找不到该值,它将尝试在父作用域中查找,以此类推。其他创建不同作用域的指令包括 ngIncludengRepeat。希望现在清楚了 :) - AlwaysALearner
我也认为使用ng-if会移除作用域,但我无法实时看到它,请您看一下这个问题,我在这里卡住了 http://stackoverflow.com/questions/27136591/how-can-i-unbindremove-angular-models-when-not-in-dom - Vinod Louis
4
哪个更适合性能?我认为ng-show和ng-hide是吗? - tom10271
显示剩余3条评论

101
也许一个有趣的观点是两者之间的优先级差异。
据我所知,ng-if指令具有所有Angular指令中最高(如果不是最高)的优先级。这意味着:它将在所有其他低优先级指令之前首先运行。它首先运行的事实意味着,在处理任何内部指令之前,元素被删除。或者至少可以这么理解。
我在为当前客户构建的UI中观察并使用了这个特性。整个UI非常密集,并且到处都有ng-show和ng-hide。不多赘述,但我构建了一个通用组件,可以使用JSON配置进行管理,因此必须在模板内部进行一些切换。存在ng-repeat,在ng-repeat内部显示一个表格,其中有许多ng-shows、ng-hides和甚至ng-switches存在。他们想要在列表中显示至少50次重复,这将导致需要处理大约1500-2000个指令。我检查了代码,Java后端+自定义JS在前端需要大约150毫秒来处理数据,然后Angular需要花费2-3秒才能显示。客户没有抱怨,但我感到震惊:)
在我的搜索中,我偶然发现了ng-if指令。现在,也许最好指出,在构思这个UI的时候,还没有ng-if可用。由于ng-show和ng-hide中都有返回布尔值的函数,我可以很容易地将它们全部替换为ng-if。通过这样做,所有内部指令似乎都不再被评估。这意味着我回到了只计算约三分之一的指令,并且UI加速到大约500毫秒-1秒的加载时间。(我无法确定确切的秒数)
请注意:指令不被评估这个事实,是我对底层发生的事情的一个猜测。因此,在我看来:如果您需要元素出现在页面上(例如:用于检查元素或其他任何情况),但仅需隐藏该元素,请使用 ng-show/ng-hide。在其他所有情况下,请使用 ng-if。

1
是的,我想这就是ng-if的目标:减少处理时间。这个指令的存在肯定不仅仅是因为一些CSS伪选择器。好文章!+1 - Liglo App

37
< p > ng-if指令从页面中删除内容,ng-show/ng-hide使用CSS的display属性隐藏内容。

这在您想要使用:first-child:last-child伪选择器进行样式设置时非常有用。


你是指使用:first和:last选择器的含义是什么? - Stephane Rolland
哎呀,我是指 :first-child:last-child。 https://developer.mozilla.org/zh-CN/docs/Web/CSS/:first-child https://developer.mozilla.org/zh-CN/docs/Web/CSS/:last-child - Andrei

16

@EdSpencer说得对。如果您有很多元素并且使用ng-if只实例化相关的元素,则可以节省资源。 @CodeHater也有一定道理,如果您经常要删除和显示一个元素,则隐藏它而不是删除它可能会提高性能。

我发现ng-if的主要用途是允许我清晰地验证和消除非法元素。例如,我可以引用空图像名称变量,这将引发错误,但是如果我使用ng-if并检查它是否为空,则一切正常。如果我使用ng-show,则仍然会触发错误。


7

关于ng-if和ng-show需要注意的一点是,在使用表单控件时最好使用ng-if,因为它会完全从DOM中删除元素。

这种差异很重要,因为如果您创建一个带有required="true"的输入字段,然后设置ng-show="false"来隐藏它,当用户尝试提交表单时,Chrome将抛出以下错误:

An invalid form control with name='' is not focusable.

由于输入字段存在且为“required”(必填),但由于其被隐藏,Chrome无法将焦点放在上面。这可能会导致代码崩溃并停止脚本执行。因此,请小心!

这是一个事实,如果你使用表单控件进行验证,那么如果你使用ng-show/ng-hide,你将会遇到很多问题。如果你有多个基于表达式的隐藏/显示部分,那么如果你使用ng-show/hide,元素仍然存在,验证将失败,尽管它们不在屏幕上。所以,ng-if可以拯救你 :) - NeverGiveUp161

5

@Gajus Kuizinas和@CodeHater是正确的。这里我只是举个例子。 当我们使用ng-if时,如果分配的值为false,则整个HTML元素将从DOM中删除。如果分配的值为true,则HTML元素将在DOM上可见。作用域与父作用域相比不同。但在ng-show的情况下,它只会根据分配的值显示和隐藏元素。但它始终留在DOM中。仅根据分配的值更改可见性。

http://plnkr.co/edit/3G0V9ivUzzc8kpLb1OQn?p=preview

希望这个示例能帮助您理解作用域。 尝试给ng-show和ng-if设置false值,并在控制台中检查DOM。 尝试在输入框中输入值并观察差异。
<!DOCTYPE html>

你好,Plunker!

<input type="text" ng-model="data">
<div ng-show="true">
    <br/>ng-show=true :: <br/><input type="text" ng-model="data">
</div>
<div ng-if="true">
    <br/>ng-if=true :: <br/><input type="text" ng-model="data">
</div> 
{{data}}


2

事实上,ng-if指令与ng-show不同的是,它会创建自己的作用域,这导致了有趣的实际差异:

angular.module('app', []).controller('ctrl', function($scope){
  $scope.delete = function(array, item){
    array.splice(array.indexOf(item), 1);
  }
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app='app' ng-controller='ctrl'>
   <h4>ng-if:</h4>
   <ul ng-init='arr1 = [1,2,3]'>
      <li ng-repeat='x in arr1'>
        {{show}}
        <button ng-if='!show' ng-click='show=!show'>Delete {{show}}</button>
        <button ng-if='show' ng-click='delete(arr1, x)'>Yes {{show}}</button>
        <button ng-if='show' ng-click='show=!show'>No</button>
      </li>
   </ul>
   
   <h4>ng-show:</h4>
   <ul ng-init='arr2 = [1,2,3]'>
      <li ng-repeat='x in arr2'>
        {{show}}
        <button ng-show='!show' ng-click='show=!show'>Delete {{show}}</button>
        <button ng-show='show' ng-click='delete(arr2, x)'>Yes {{show}}</button>
        <button ng-show='show' ng-click='show=!show'>No</button>
      </li>
   </ul>
   
   <h4>ng-if with $parent:</h4>
    <ul ng-init='arr3 = [1,2,3]'>
      <li ng-repeat='item in arr3'>
        {{show}}
        <button ng-if='!show' ng-click='$parent.show=!$parent.show'>Delete {{$parent.show}}</button>
        <button ng-if='show' ng-click='delete(arr3, x)'>Yes {{$parent.show}}</button>
        <button ng-if='show' ng-click='$parent.show=!$parent.show'>No</button>
      </li>
   </ul>
</div>

在第一个列表中,on-click事件会改变来自内部/自有作用域的show变量,但是ng-if正在监视另一个具有相同名称的来自外部作用域的变量,因此解决方案不起作用。在ng-show的情况下,我们只有一个show变量,这就是为什么它能够正常工作的原因。要修复第一次尝试,我们应该通过$parent.show引用来自父级/外部作用域的show


1

ng-show 和 ng-hide 是相反的。但是 ng-hide 或 ng-show 与 ng-if 的区别在于,如果我们使用 ng-if,那么元素将会在 DOM 中创建,但是使用 ng-hide/ng-show 元素将完全被隐藏。

ng-show=true/ng-hide=false:
Element will be displayed

ng-show=false/ng-hide=true:
element will be hidden

ng-if =true
element will be created

ng-if= false
element will be created in the dom. 

1
  1. ng-if如果为false,则会从DOM中删除元素。这意味着附加到这些元素的所有事件和指令都将丢失。例如,对于子元素之一的ng-click,当ng-if评估为false时,该元素将从DOM中删除,并且当它为true时,它将被重新创建。

  2. ng-show/ng-hide不会从DOM中删除元素。它使用CSS样式(.ng-hide)来隐藏/显示元素。这样,附加到子元素的事件和指令将不会丢失。

  3. ng-if创建一个子作用域,而ng-show/ng-hide则不会。


0

ngIf 通过移除或重新创建元素对 DOM 进行操作。

ngShow 应用 CSS 规则来显示/隐藏元素。

对于大多数情况(并非总是如此),我会总结如下:如果您需要进行一次性检查以显示/隐藏元素,则使用 ng-if,如果您需要基于用户在屏幕上的操作来显示/隐藏元素(例如选中复选框,然后显示文本框,取消选中则隐藏文本框等),那么请使用 ng-show


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接