【问题标题】:Angularjs - ng-cloak/ng-show elements blinkAngularjs - ng-cloak/ng-show 元素闪烁
【发布时间】:2012-06-30 06:37:05
【问题描述】:

我在 angular.js 中遇到指令/类 ng-cloakng-show 的问题。

Chrome 工作正常,但 Firefox 导致带有 ng-cloakng-show 的元素闪烁。 恕我直言,这是由于将ng-cloak/ng-show 转换为style="display: none;" 造成的,可能是 Firefox javascript 编译器有点慢,所以元素会出现一段时间然后隐藏?

例子:

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

【问题讨论】:

  • 如果您最初在这些元素上设置了 display:none 样式,是否可以解决问题?
  • 我会试试的,我正在尝试添加类(隐藏元素)然后通过 js 手动删除它,但它看起来更糟糕。

标签: javascript class angularjs


【解决方案1】:

虽然文档没有提到它,但将 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; 的规则,则 Bootstrap 的规则将优先,并且 display 将设置为 block,因此您会在模板编译之前看到闪烁。

【讨论】:

  • 另请注意,如果您使用异步加载器(例如 require.js)加载 angular.js,可能会发生同样的问题,因为 .js 中的 css 规则不会被及时解析。上面的解决方案也解决了这种情况。
  • 不能为我解决问题。不知道 - 我认为浏览器太急于一开始就展示东西......
  • 浏览器不应该在不考虑css的情况下渲染DOM,即使是第一遍;那将是非常低效的;仔细检查您的设置:p
  • 当你延迟加载 dom 模块代码后,你如何重新引导已经被 ng-cloaked 的 dom?
  • 如果上面的 css 对你不起作用,你的 : 中的 ng:cloak 可能没有正确转义。对于纯 CSS,请确保存在反斜杠。对于已编译的 css,例如手写笔,它将是[ng\\:cloak]。检查你编译的 CSS 以确保它是正确的。
【解决方案2】:

作为mentioned in the documentation,您应该在您的CSS 中添加一条规则以根据ng-cloak 属性隐藏它:

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

我们在“Built with Angular”网站上使用了类似的技巧,你可以在 Github 上查看源代码:https://github.com/angular/builtwith.angularjs.org

希望有帮助!

【讨论】:

  • angular.js 将该样式规则添加到文档的头部。你真的不需要把它添加到你的 CSS 中。也就是说,这似乎有效。我的猜测是因为 angular.js 在加载 angular 之前不会将样式块添加到头部。
  • 文档中提到的真正是这样的:“为了获得最佳结果,必须在 html 文件的 head 部分加载 angular.js 脚本;或者,css 规则(上)必须包含在应用程序的外部样式表中。”
  • 换句话说,如果您在页面底部添加脚本引用(很多人都这样做);然后将规则添加到您的 CSS。
  • 我在 require.js 中添加了 angular.js,所以这对我有帮助。
  • 将 ng-cloak 指令添加到包含 ng-app 指令的 html 元素中。像魅力一样工作。示例:
【解决方案3】:

确保 AngularJS 包含在 HTML 的 head 中。见ngCloak doc

为了获得最佳效果,必须在头部加载 angular.js 脚本 html文件的部分;或者,CSS规则(上面)必须是 包含在应用程序的外部样式表中。

【讨论】:

  • 是的!我不明白为什么世界各地的人似乎都建议在页面末尾加载 angular.js。如果 Angular 从一开始就掌握控制权,我会感觉更好。我的ng-cloak 正在工作。
  • 我同意 - 最后加载脚本的事情来自正常的 Web 开发,您希望页面在 js 执行其操作之前显示某些内容,但在 Angular 的情况下,您实际上想要反过来。
  • AND 在加载任何样式表之前。在 head 中包含 Angular,但在包含样式表之后,并不能解决问题。
【解决方案4】:

我在使用 ngCloak 时运气不佳。尽管上面提到了一切,我仍然会闪烁。避免轻弹的唯一可靠方法是将您的内容放在模板中并包含该模板。在 SPA 中,在被 Angular 编译之前唯一会被评估的 HTML 是你的主 index.html 页面。

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

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

您不应该以这种方式出现任何闪烁,因为 Angular 会在将模板添加到 DOM 之前对其进行编译。

【讨论】:

  • 正是我使用的 - 干净简单,没有痛苦的黑客攻击。
  • 请注意ng-include 会产生一个额外的 AJAX 请求以从服务器获取内容。例如,我学到了你永远不应该在ng-repeat 中使用ng-include 的艰难方法。
  • 为我工作。请记住将 ng-app 保留在标记中的 ng-include 之外。
  • 这个解决方案效果最好,没有任何问题。如果可行,请使用此解决方案。
  • 这个解决方案解决了一个非常烦人的情况。谢谢!
【解决方案5】:

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>

【讨论】:

  • 不错,简单的答案。 ng-bind 是避免“花括号闪烁”或必须在标签级别使用 ng-cloak 的好方法,尽管有些人认为这会降低代码的可读性。对于他们来说,我认为没有理由不将这两种方法混合使用。
  • ng-bind 是解决问题的更好方法,因为其他答案要求您加载第一个角度,在任何情况下都没有花括号闪烁
【解决方案6】:

如果您使用另一种触发 ng-cloak 的方法,除了接受的答案...

您可能还希望为您的 CSS/LESS 添加一些额外的特性:

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

【讨论】:

  • 这适用于我的用例,但上述方法似乎都不起作用。
【解决方案7】:

我有一个类似的问题,发现如果你有一个包含转换的类,元素会闪烁。我尝试添加 ng-cloak 没有成功,但是通过删除转换按钮停止闪烁。

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

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

只需覆盖类即可移除过渡,按钮将停止闪烁。

更新

再次在 ionic 上使用 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

【讨论】:

  • 但这不会禁用 ng-hide/show 指令的动画吗?
  • 我不记得了。你试过了,它禁用了动画?
  • 谢谢。这是关于离子的一个非常特殊的问题。我在我的 scss 中添加了 .button-clear, .button-icon, .button-outline { @include transition(opacity 0s); }
【解决方案8】:

我遇到了一个问题,在 ng-show 指令有机会运行之前,&lt;div ng-show="expression"&gt; 最初会在几分之一秒内可见,即使“表达式”最初是错误的。

我使用的解决方案是手动添加“ng-hide”类,如&lt;div ng-show="expression" ng-hide&gt;,以确保它最初是隐藏的。之后,ng-show 指令将根据需要添加/删除 ng-hide 类。

【讨论】:

  • 哇,在我尝试过的所有可怕选项中,这成功了。谢谢!
  • 最佳解决方案!这让我疯狂了几个月!谢谢!
  • 我正在使用离子框架,这是唯一有效的答案
【解决方案9】:

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

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

【讨论】:

  • 是的,这是为我做的,谢谢!
  • 谢谢,这让我发疯了。奇怪的错误
【解决方案10】:

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

问题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。

听起来 Problem 1 是 OP 遇到的问题,但其他人发现解决方案不起作用或仅部分起作用,因为他们正在解决 Problem 2或者也一样。

重要提示:确保将解决方案应用于 ng-cloak 应用得太晚和很快被移除的情况。仅解决其中一个问题可能无法缓解症状。

【讨论】:

  • 这为我修复了它“必须在头部加载脚本”
【解决方案11】:

我们在公司遇到了这个问题,并通过在那些闪烁的 ng-show 元素的 CSS 样式中添加“display: none”来解决它。我们根本不需要使用 ng-cloak。与本主题中的其他人不同,我们在 Safari 中遇到了这个问题,但在 Firefox 或 Chrome 中没有遇到这个问题——可能是由于Safari's lazy repaint bug in iOS7

【讨论】:

    【解决方案12】:

    对于它的价值,我有一个类似的问题 ng-cloak 不起作用。可能值得检查启用缓存的应用/站点以重用源文件,看看是否有帮助。

    在闪烁的情况下,我在 DevTools 打开并禁用缓存的情况下进行测试。在启用缓存的情况下关闭面板解决了我的问题。

    【讨论】:

      【解决方案13】:

      将以下语句保留在 head 标签中修复了此问题

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

      official documentation

      【讨论】:

        【解决方案14】:

        我无法让这些方法中的任何一个起作用,所以我最终做了以下事情。对于您最初想要隐藏的元素:

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

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

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

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

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

        【讨论】:

          【解决方案15】:

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

          【讨论】:

          • 但它也破坏了该部分 dom 上的任何正在运行的插件......(例如:jquery ui)
          【解决方案16】:

          【讨论】:

            【解决方案17】:

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

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

            【讨论】:

              【解决方案18】:

              我尝试了上面的 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>
              

              【讨论】:

                【解决方案19】:

                除了其他答案之外,如果您发现模板代码的闪烁仍然存在,则很可能您的脚本位于页面底部,这意味着直接向上的 ng-cloak 指令将不起作用。您可以将脚本移到头部或创建 CSS 规则。

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

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

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

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

                【讨论】:

                  【解决方案20】:

                  我尝试了此处发布的所有解决方案,但在 Firefox 中仍然闪烁。

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

                  【讨论】:

                  • 我发现这是唯一对我有用的解决方案,但我想避免使用 JQuery,所以找到了替代方案。在这里查看我的答案:stackoverflow.com/a/42527700/4214694
                  【解决方案21】:

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

                  核心选项:手动隐藏内容

                  使用显式 CSS 是最好的选择,因此不需要以下内容。但我会在这里提到它,因为它提供了一些见解,您可以在加载其他框架或在您自己的基于标记的模板中手动隐藏/显示内容。

                  在我发现我可以将 CSS 样式显式嵌入到页面中之前,我曾试图弄清楚为什么 ng-cloak 没有完成它的工作。在浪费了一个小时无处可去之后,我终于决定手动隐藏和显示容器。这个想法很简单——最初隐藏容器,然后在 Angular 完成初始处理并从页面中删除模板标记后显示它。

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

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

                  注意 display: 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
                  【解决方案22】:

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

                  【讨论】:

                    【解决方案23】:

                    从上面的讨论来看

                    [ng-cloak] {
                                    display: none;
                                }
                    

                    是解决问题的完美方法。

                    【讨论】:

                      【解决方案24】:

                      我在指令中使用 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 插入操作。这样做的代价是为了同一目的使用两个范围变量而不是一个,但到目前为止,这绝对是最好的选择。

                      【讨论】:

                        【解决方案25】:

                        尝试了ng-cloak,但仍然短暂闪烁。下面的代码完全摆脱了它们。

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

                        【讨论】:

                          【解决方案26】:

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

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

                          在这种情况下,基本上当 scope.watch 被触发时,AngularJS 会监控名称变量(model.value)的变化

                          【讨论】:

                            【解决方案27】:

                            我会用&lt;div ng-cloak&gt; 包装&lt;ul&gt;

                            【讨论】:

                            • 他不需要包装&lt;ul&gt;ng-cloak 将隐藏它应用到的任何元素,以及该元素的后代。
                            【解决方案28】:

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

                            以前是&lt;div class="options-modal" ng-show="showOptions"&gt;&lt;/div&gt;

                            现在是:&lt;div class="options-modal" ng-class="{'show': isPrintModalShown}"&gt;

                            options-modal 类的 CSS 默认为 display: none。 show 类包含display:block CSS。

                            【讨论】:

                              【解决方案29】:

                              避免换行

                              <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';">
                              

                              【讨论】:

                                猜你喜欢
                                • 2015-07-07
                                • 1970-01-01
                                • 2014-12-08
                                • 2014-03-27
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                相关资源
                                最近更新 更多