AngularJS - 直到DOM加载完成之前隐藏内容

68

在Angularjs中,我的HTML在从服务器返回数据之前会出现闪烁问题。

这里有一个视频展示了这个问题:http://youtu.be/husTG3dMFOM - 请注意 #| 和右侧的灰色区域。

我尝试了ngCloak,但没有成功(虽然ngCloak确实可以防止承诺的括号出现),并且想知道隐藏内容直到由Angular填充HTML的最佳方法。

我在我的控制器中使用了这段代码,让它可以正常工作:

var caseCtrl = function($scope, $http, $routeParams) {
    $('#caseWrap').hide(); // hides when triggered using jQuery
    var id = $routeParams.caseId;

    $http({method: 'GET', url: '/v1/cases/' + id}).
        success(function(data, status, headers, config) {                   
            $scope.caseData = data;

            $('#caseWrap').show(); // shows using jQuery after server returns data
        }).
        error(function(data, status, headers, config) {
            console.log('getCase Error', arguments);
        });
}

我听说过很多次不要从控制器操作DOM。我的问题是,如何使用指令来实现这一点?换句话说,如何在所有内容从服务器加载完成之前隐藏指令所附加的元素?


嘿,我觉得现在这个答案应该被接受了 ;) https://dev59.com/QWMl5IYBdhLWcg3wyJYe#25586922 - Sebastien Horin
6个回答

148

在您的CSS中添加:

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

只需像这样将“ng-cloak”属性添加到您的div中:

<div id="template1" ng-cloak>{{scoped_var}}<div>

文档:https://docs.angularjs.org/api/ng/directive/ngCloak


3
ng-cloak!只需要翻译这个词就可以了 :) (注:ng-cloak是AngularJS框架中的一个指令,用于在页面加载时隐藏未经编译的AngularJS标记。) - bresleveloper
4
很好,救了我一个大麻烦。 - Demodave
6
非常感谢。Angular文档在此方面不是很清楚,看起来他们说CSS已经被嵌入了,但实际上并没有。感谢您的提示! - alcfeoh
不错,问题已解决 :) - PHP Ninja

10
在您的caseWrap元素上,添加“ng-show =” contentLoaded“”,然后在当前位置使用“$('#caseWrap').show();” 的地方,替换为“$scope.contentLoaded = true;”。如果caseWrap元素在此控制器之外,则可以使用$rootScopeevents执行相同类型的操作。

8
请将以下内容添加到您的CSS中:
[ng\:cloak],[ng-cloak],.ng-cloak{display:none !important}

您的angular模板编译速度不够快。

更新

在您的控制器中不应进行DOM操作。您可以做两件事... 1. 您可以通过指令拦截控制器范围内的值更改!在您的情况下,创建一个作为属性指定要监视的属性的指令。在您的情况下,它将是caseData。如果casedata为falsey,则隐藏它。否则,显示它。

  1. 更简单的方法是只使用ngShow='casedata'。

代码

var myApp = angular.module('myApp', []);
myApp.controller("caseCtrl", function ($scope, $http, $routeParams, $timeout) {
    $scope.caseData = null;
    //mimic a delay in getting the data from $http
    $timeout(function () {
        $scope.caseData = 'hey!';
    }, 1000);

})
    .directive('showHide', function () {
    return {
        link: function (scope, element, attributes, controller) {
            scope.$watch(attributes.showHide, function (v) {
                if (v) {
                    element.show();
                } else {
                    element.hide();
                }
            });
        }
    };
});

HTML

<div ng-controller='caseCtrl' show-hide='caseData'>using directive</div>
<div ng-controller='caseCtrl' ng-show='caseData'>using ngShow</div>

JSFIDDLE:http://jsfiddle.net/mac1175/zzwBS/


1
@ScottyBollinger 我也应该告诉你不要在控制器中进行DOM操作。这被认为是一种不好的做法。(请参见http://docs.angularjs.org/guide/dev_guide.mvc.understanding_controller中的“正确使用控制器”部分)。我很快会更新我的答案,告诉你如何解决这个问题... - mitch

2

既然您要求指令,那么请尝试这个。

.directive('showOnLoad', function() {
  return {
    restrict: 'A',
    link: function($scope,elem,attrs) {

      elem.hide();

      $scope.$on('show', function() {
        elem.show();
      });

    }
  }
});

将(show-on-load)粘在你的元素上,在你的控制器中注入$rootScope,并在html加载完成时使用此广播事件。

$rootScope.$broadcast('show');

谢谢回复。上面的答案更高效。我只是之前不知道可以用ngShow指令实现,所以才问是否有新的指令。 - Scotty Bollinger

1
我使用了Zack的回复来创建一个“加载”指令,这可能对一些人有用。
模板:
<script id="ll-loading.html" type="text/ng-template">
  <div layout='column' layout-align='center center'>
    <md-progress-circular md-mode="indeterminate" value="" md-diameter="52"></md-progress-circular>
  </div>
</script>

指令:

    directives.directive('loading', function() {
  return {
    restrict: 'E',
    template: 'll-loading.html',
    link: function($scope,elem,attrs) {

      elem.show();

      $scope.$on('loaded', function() {
        console.log("loaded: ");
        elem.hide();
      });

    }
  }
});

这个例子在HTML中使用了angular-material。

0

被接受的答案对我没用。我有一些元素带有ng-show指令,即使使用了ng-cloak,这些元素仍然会短暂地显示出来。似乎在ng-show返回false之前,ng-cloak已经被解决了。将ng-hide类添加到我的元素中解决了我的问题。


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