AngularJS-ng-cloak / ng-show元素闪烁


231

我在angular.js中使用指令/类ng-cloak或的问题ng-show

Chrome可以正常运行,但是Firefox会通过ng-cloak或导致元素闪烁ng-show。恕我直言,它是由引起的转换ng-cloak/ ng-showstyle="display: none;",可能是Firefox的JavaScript编译器是有点慢,所以元素出现了一会儿,然后躲起来?

例:

<ul ng-show="foo != null" ng-cloak>..</ul>

1
如果最初在这些元素上设置display:none样式,是否可以解决问题?
akonsu 2012年

3
我会尝试的,我正在尝试与添加类(隐藏元素)然后通过js手动删除它类似的操作,但是看起来更糟。
MelkorNemesis

Answers:


385

尽管文档中没有提及,但仅将display: none;规则添加到CSS 可能还不够。如果您要在主体中加载angular.js或模板编译得不够快,请使用ng-cloak指令,在CSS中添加以下内容:

/* 
  Allow angular.js to be loaded in body, hiding cloaked elements until 
  templates compile.  The !important is important given that there may be 
  other selectors that are more specific or come later and might alter display.  
 */
[ng\:cloak], [ng-cloak], .ng-cloak {
  display: none !important;
}

如评论中所提到的,!important至关重要。例如,如果您具有以下标记

<ul class="nav">
  <li><a href="/foo" ng-cloak>{{bar}}</a></li>
</ul>

并且您碰巧正在使用bootstrap.css,以下选择器更适合您ng-cloak的ed元素

.nav > li > a {
  display: block;
}

因此,如果您在display: none;simple中包含一个规则,Bootstrap的规则将具有优先级,并且display会被设置为block,因此您将在模板编译之前看到闪烁。


3
另请注意,如果使用异步加载程序(例如require.js)加载angular.js,也会发生相同的问题,因为.js中的css规则将无法及时解析。上面的解决方案也解决了这种情况。
2013年

84
不能为我解决问题。不知道-我认为浏览器太急于最初显示内容...
Andriy Drozdyuk

7
即使在初次通过时,浏览器也不应在不考虑css的情况下呈现DOM。那将是非常低效的;仔细检查您的设置:p
AlexG

1
一旦您延迟加载了doms模块代码,您如何重新引导已被ng隐藏的dom?
FutuToad 2014年

如果上面的CSS是不适合你的工作机会是你:ng:cloak没有正确转义。对于纯CSS,请确保存在反斜杠。对于已编译的CSS,例如Stylus,它将为[ng\\:cloak]。检查您编译的CSS,以确保它是正确的。

47

文档中所述,您应该在CSS上添加一个规则以基于ng-cloak属性将其隐藏:

[ng\:cloak], [ng-cloak], .ng-cloak {
    display: none;
}

我们在“使用Angular构建”网站上使用了类似的技巧,您可以在Github上查看其来源:https : //github.com/angular/builtwith.angularjs.org

希望有帮助!


4
angular.js将该样式规则添加到文档的开头。您确实不需要将其添加到CSS中。也就是说,这似乎有效。我的猜测是因为angular.js直到加载angular之后才将样式块添加到头部。
ntownsend 2012年

13
什么是真正的文件中提到的是这样的:“为了达到最佳效果,angular.js脚本必须在HTML文件的头部被加载; 或者,在CSS规则(上)必须包含在应用程序的外部样式表。 ”
安德烈Drozdyuk

4
换句话说,如果您要在页面底部添加脚本引用(就像很多人一样);然后将规则添加到CSS。
GFoley83

1
我添加了angular.js和require.js,所以这对我有所帮助。
橄榄色

1
在包含ng-app指令的html元素中添加了ng-cloak指令。像魅力一样工作。例如:<div ng-cloak ng-app =“ my-app”>
miniscem '16

33

确保AngularJS包含在headHTML中。参见ngCloak doc

为了获得最佳结果,必须将angular.js脚本加载到html文件的头部;或者,必须在应用程序的外部样式表中包含上述css规则。


3
是!我不明白为什么所有地方的人似乎都建议在页面末尾加载angular.js。如果Angular从一开始就掌握控制权,我会感觉更好。我ng-cloak现在在工作。
伊万·费雷尔

2
我同意-有关在脚本最后加载的问题来自正常的Web开发,您希望页面在js执行其操作之前显示某些内容,但对于有角度的情况,您实际上希望相反。

1
在加载任何样式表之前,请输入AND。head在样式表中包含但之后包含Angular 并不能解决问题。
AgmLauncher '16

27

使用ngCloak从来没有让我很幸运。尽管上述所有内容,我仍然会忽悠。避免轻拂的唯一肯定方法是将您的内容放入模板中并包括该模板。在SPA中,唯一由Angular编译之前将被评估的HTML是您的主要index.html页面。

只需将体内的所有东西都粘在一个单独的文件中,然后:

<ng-include src="'views/indexMain.html'"></ng-include>

您永远都不会那样闪烁,因为Angular在将模板添加到DOM之前会对其进行编译。


1
正是我所使用的-干净简单,没有痛苦的黑客。
Dmitri Zaitsev 2014年

2
请注意,这会ng-include产生一个额外的AJAX请求,以从服务器获取内容。例如,我了解了一种绝不应该ng-include在内部使用的艰难方法ng-repeat
jsuddsjr 2014年

1
为我工作。记得把ng-app外面ng-include在您的标记。
GraehamF,2015年

2
此解决方案最有效,不会出现任何故障。如果可行,请使用此解决方案。
idungotnosn 2015年

2
该解决方案解决了一个非常烦人的情况。谢谢!
麦克斯韦

22

ngBindngBindTemplate是不需要CSS的替代方法:

<div ng-show="foo != null" ng-cloak>{{name}}</div>  <!-- requires CSS -->
<div ng-show="foo != null" ng-bind="name"></div>
<div ng-show="foo != null" ng-bind-template="name = {{name}}"></div>

1
不错,简单的答案。ng-bind这是避免“大括号闪烁”或不得不ng-cloak在标签级别使用的一种好方法,尽管有些人认为这会使代码的可读性降低。对于他们来说,我看不出不将两种方法混合使用的理由。
戴夫·埃弗里特

1
ng-bind是解决该问题的更好方法,因为其他答案要求您先加载有角度的支撑,无论在任何情况下都不会出现大括号
legramira 2015年

20

除了可接受的答案之外,如果您使用触发ng-cloak的替代方法...

您可能还希望为CSS / LESS添加一些其他特性:

[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
.ng-cloak, .x-ng-cloak,
.ng-hide {
    display: none !important;
}

1
当上述情况似乎都不起作用时,这适用于我的用例。
Porlune,2016年

15

我有一个类似的问题,发现如果您有一个包含过渡的类,则该元素将闪烁。我尝试添加ng-cloak失败,但是通过删除过渡按钮停止了闪烁。

我正在使用离子框架,按钮轮廓具有此过渡

.button-outline {
  -webkit-transition: opacity .1s;
  transition: opacity .1s;
}

只需覆盖该类以删除过渡,按钮将停止闪烁。

更新资料

同样,在使用ng-show / ng-hide时,在离子上也有闪烁。添加以下CSS即可解决该问题:

.ng-hide-add,
.ng-hide-remove {
  display: none !important;
}

资料来源:http//forum.ionicframework.com/t/beta-14-ng-hide-show/14270/9


1
但这是否会禁用ng-hide / show指令的动画?
库沙格拉·古尔

1
我不记得了 您尝试过并禁用了动画吗?
Seb Fanals 2015年

1
谢谢。这是关于离子的非常特殊的问题。我添加.button-clear, .button-icon, .button-outline { @include transition(opacity 0s); }到我的scss。
hgoebl 2015年

9

我有一个问题 <div ng-show="expression">,即即使ng-show指令有机会运行之前,即使“ expression”最初是假的,a最初也会在不到一秒钟的时间内可见。

我使用的解决方案是手动添加“ ng-hide”类(如中)<div ng-show="expression" ng-hide>,以确保其最初开始处于隐藏状态。之后,ng-show指令将根据需要添加/删除ng-hide类。


1
哇,在我尝试过的所有怪胎中,这确实成功了。谢谢!
尼古拉

最好的解决方案!这让我发疯了几个月!谢谢!
abelabbesnabi

我使用的是离子框架,这是唯一有效的答案
Mikel

7

尝试关闭Firebug。我是认真的。这对我来说很有帮助。

应用接受的答案,然后确保Firefox 中的Firebug关闭:按F12键,然后关闭此页面的Firebug-右上角的小按钮。


是的,为我做到了,谢谢!
MadeInDreams '16

谢谢,这让我发疯。奇怪的错误
Stephen Simpson

6

实际上,有两个单独的问题可能导致闪烁问题,您可能会遇到其中一个或两个。

问题1:应用ng-cloak太晚

解决此问题的方法已在此页上的许多答案中进行了描述,以确保将AngularJS加载到头部。参见ngCloak doc

为了获得最佳结果,必须将angular.js脚本加载到html文件的头部;或者,必须在应用程序的外部样式表中包含上述css规则。

问题2:过早移除ng-cloak

当页面上有很多CSS且规则相互层叠,并且在应用顶层之前,更深层的CSS会闪烁时,很可能会发生此问题。

style="display:none"只要样式删除得足够晚,答案中涉及添加到元素中的jQuery解决方案就可以解决此问题(实际上,这些解决方案都解决了这两个问题)。但是,如果您不想将样式直接添加到HTML中,则可以使用实现相同的结果ng-show

从问题的示例开始:

<ul ng-show="foo != null" ng-cloak>..</ul>

向您的元素添加其他ng-show规则:

<ul ng-show="isPageFullyLoaded && (foo != null)" ng-cloak>..</ul>

(您需要ng-cloak避免出现问题1)。

然后在您的app.run中设置isPageFullyLoaded

app.run(['$rootScope', function ($rootScope) {
    $rootScope.$safeApply = function (fn) {
        $rootScope.isPageFullyLoaded = true;
    }
}]);

请注意,取决于您正在执行的操作,app.run可能是设置的最佳位置,也可能不是最佳位置isPageFullyLoaded。重要的是要确保isPageFullyLoaded在您不想闪烁的任何内容准备好向用户显示之后将其设置为true。

听起来问题1是OP遇到的问题,但是其他人则发现解决方案不起作用或仅部分起作用,因为他们替代地或同样是问题2

重要说明:请确保同时应用ng-cloak的解决方案为时已晚,然后将其移除。仅解决这些问题之一可能无法缓解症状。


1
这为我修复了此问题“脚本必须加载到头部”
aliopi

4

我们在公司遇到了这个问题,并通过为闪烁的ng-show元素的CSS样式添加“ display:none”来解决了这个问题。我们根本不需要使用ng-cloak。与该线程中的其他线程不同,我们在Safari中遇到了此问题,但在Firefox或Chrome中却没有遇到过这个问题-可能是由于Safari在iOS7中的懒惰重绘错误所致


3

对于它的价值,我遇到了类似的问题ng-cloak无法正常工作。可能值得检查一下启用了缓存以重用源文件的应用程序/站点,以查看是否有帮助。

我的磨合伴随着闪烁,我正在测试DevTools打开并禁用缓存。通过启用缓存使面板保持关闭状态可以解决我的问题。


3

将以下语句保留在head标签中可解决此问题

<style type="text/css">
    [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
    display: none !important;
}
</style>

官方文件


3

我无法使用这些方法中的任何一种,因此最终我做了以下工作。对于最初要隐藏的元素:

<div <!--...--> style="display: none;" ng-style="style">

然后在您的控制器中,将其添加到顶部或顶部附近:

$scope.style = { display: 'block' };

这样,该元素最初是隐藏的,仅在实际运行控制器代码时显示。

您可以根据需要调整布局,也许可以添加一些逻辑。就我而言,如果当前尚未登录,我会切换到登录路径,并且不希望我的界面事先闪烁,因此我$scope.style在登录检查后进行设置。


2

最好使用ng-if代替ng-showng-if 完全删除并重新创建DOM中的元素,并有助于避免ng-show闪烁。


但是它也会破坏dom那个部分上所有正在运行的插件...(例如:jquery ui)
Geert Bellemans


2

您最好参考角度文档,因为version [1.4.9]已更新至以下版本,使其可以支持data-ng-cloak指令。

[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
  display: none !important;
}

2

我尝试了上面的ng-cloak解决方案,但是Firefox仍然存在间歇性问题。对我有用的唯一解决方法是将窗体的加载延迟到Angular完全加载为止。

我只是在应用程序中添加了ng-init,并在表单一侧使用ng-if来检查我设置的变量是否已经加载。

<div ng-app="myApp" ng-init="loaded='yes'"> 
   <form ng-if="loaded.length > 0">
      <!--all my elements here-->
   </form>
</div>

1

除了其他答案以外,如果您发现模板代码仍在闪烁,则很有可能您的脚本位于页面底部,这意味着直接将ng-cloak指令无效。您可以将脚本移到最前面,也可以创建CSS规则。

文档说:“为了获得最佳结果,必须将angular.js脚本加载到html文档的头部;或者,上述css规则必须包含在应用程序的外部样式表中。”

现在,它不必是外部样式表,而只需在头部的一个元素中即可。

<style type="text/css">
  .ng-cloak {
    display: none !important;
  }
</style>

来源:https : //docs.angularjs.org/api/ng/directive/ngCloak


1

我尝试过这里发布的所有解决方案,但在Firefox中仍然闪烁。

如果对任何人都有style="display: none;"用,我可以通过添加到主要内容div中来解决它,然后$('#main-div-id').show();在从服务器获取数据后加载所有内容,然后使用jQuery(我已经在页面上使用过它)了。


我发现这是唯一对我有用的解决方案,但是我想避免使用JQuery,因此找到了替代方法。在这里查看我的答案:stackoverflow.com/a/42527700/4214694
Andrew Downes

1

我实际上发现Rick Strahl的Web日志中的建议完美地解决了我的问题(因为有时ng-cloak闪烁原始{{code}}仍然很奇怪,尤其是在运行Firebug时):

核选项:手动隐藏内容

使用显式CSS是最佳选择,因此以下内容永远都不是必需的。但我将在这里提及它,因为它提供了一些见识,使您可以了解如何在加载其他框架时或在您自己的基于标记的模板中手动隐藏/显示内容。

在我确定可以将CSS样式明确地嵌入到页面之前,我曾尝试弄清​​ng-cloak为什么不做它的工作。在浪费了一个小时之后,我终于决定只手动隐藏并显示容器。这个想法很简单–首先隐藏容器,然后在Angular完成初始处理并从页面中删除模板标记后再显示它。

您可以手动隐藏内容,并在Angular获得控制后使其可见。为此,我使用了:

<div id="mainContainer" class="mainContainer boxshadow"
    ng-app="app" style="display:none">

请注意显示:none样式最初在页面上显式隐藏了元素。

然后,一旦Angular运行了其初始化并有效地处理了页面上的模板标记,便可以显示内容。对于Angular,此“就绪”事件是app.run()函数:

app.run( function ($rootScope, $location, cellService) {        
    $("#mainContainer").show();
    
});

这有效地删除了display:none样式和内容显示。到app.run()触发时,DOM已准备好显示已填充数据或至少为空数据– Angular已获得控制权。


我发现这是唯一对我有用的解决方案,但是我想避免使用JQuery,因此找到了替代方法。在这里查看我的答案:stackoverflow.com/a/42527700/4214694
Andrew Downes

1

我尝试了以上所有答案,但没有任何效果。使用ionic来开发混合应用程序,并试图使错误消息不闪烁。 我最终通过在元素中添加ng-hide类来解决了我的问题。 当出现错误时,我的div已经具有ng-show来显示元素。添加ng-hide会将div设置为在加载角度之前不显示。无需ng-斗篷或增加头部角度。



1

我在指令中使用ng-show来显示和隐藏弹出窗口。

<div class="..." ng-show="showPopup">

以上都不对我有用,使用ng-if代替ng-show可能会过分。这意味着每次单击都将整个弹出内容删除并将其添加到DOM中。相反,我在同一个元素中添加了ng-if,以确保它不会在文档加载时显示:

<div class="..." ng-show="showPopup" ng-if="popupReady">

之后,我将初始化添加到负责该指令的控制器中并带有超时:

$timeout(function () {
    $scope.popupReady = true;
});

这样,我消除了闪烁的问题,避免了每次单击都需要进行昂贵的DOM插入操作。这是以牺牲两个作用域变量用于同一目的而不是一个目的为代价的,但是到目前为止,这绝对是最好的选择。


1

尝试过ng-cloak但仍然短暂眨眼。下面的代码彻底摆脱了它们。

<body style="display:none;" ng-style="{'display':'block'}">

1

上面列出的解决方案都不适合我。然后,我决定查看实际功能,并意识到,当“ $ scope.watch”被触发时,它是在name字段中输入了一个值,但实际情况并非如此。所以在代码中我设置了oldValue和newValue然后

$scope.$watch('model.value', function(newValue, oldValue) {
if (newValue !== oldValue) {
validateValue(newValue);
}
});

本质上,在这种情况下,在触发scope.watch时,AngularJS监视对名称变量(model.value)的更改


0

我会<ul><div ng-cloak>


2
他不需要包装纸袋<ul>ng-cloak会遮盖它所应用的任何元素以及该元素的后代。
btford

0

我个人决定使用ng-class属性而不是ng-show。我在这条路线上取得了很多成功,特别是对于默认情况下始终不显示的弹出窗口。

曾经是 <div class="options-modal" ng-show="showOptions"></div>

就是现在: <div class="options-modal" ng-class="{'show': isPrintModalShown}">

display: none默认情况下,options-modal类的CSS为默认值。show类包含display:blockCSS。


-2

避免换行

<meta http-equiv="Content-Security-Policy"              content="
default-src 'FOO';   
script-src 'FOO';    
style-src  'FOO'; 
font-src 'FOO';">

适用于Firefox 45.0.1

<meta http-equiv="Content-Security-Policy"              content="    default-src 'FOO';    script-src 'FOO';     style-src  'FOO';    font-src 'FOO';">
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.