Angular的ng-if或ng-show响应缓慢(2秒延迟?)

88

当请求正在处理时,我想在按钮上显示或隐藏一个加载指示器。我通过在请求正在加载或已完成加载时更改 $scope.loading 变量来使用 Angular 实现此目的。

 $scope.login = function(){
     $scope.loading = true;
    apiFactory.getToken()
        .success(function(data){
            
        })
        .error(function(error){
            
        })
         .finally(function(){
               $timeout(function() {
                 $scope.loading = false;
               }, 0);
         });
 };

在前端:

<button ng-disabled="loading" class="button button-outline button-positive" type="submit">
Log in 
<span ng-if="loading" class="ion-refreshing"></span>
</button>

这个功能很好,但是加载图标(ion-refreshing)会显示大约2秒钟,而$scope变量立即更新。我尝试了$scope.$apply,但似乎不是问题所在,作用域在请求后立即更新得很好。只是图标没有足够快地响应。


2
有任何动画涉及吗? - tasseKATT
否定。没有涉及到动画。使用ng-class似乎有所帮助。 - Jorre
我遇到了相同或类似的问题。作用域立即并正确地更新 - 我通过从 $scope 函数记录消息来验证了这一点,而这些函数是 ng-if 用于确定是否应显示相关元素。但是,带有 ng-if 的按钮保持不正确可见或隐藏,一段时间后才全部采取其预期的可见/隐藏状态。 - 我通过使用 ng-hide 解决了这个问题。Angular 版本为 1.2.16。 - KajMagnus
有没有任何解决方案适用于那些不使用任何动画效果的人? - Zia Ul Rehman Mughal
7个回答

126
尝试从您的应用配置和index.html页面中删除ngAnimate,如果您没有使用它:

angular.module('myApp', [...'ngAnimate',...])

@Spock;如果您仍需要使用ngAnimate,则保持应用程序配置不变,只需添加以下CSS:

@Spock; 如果您仍需要使用ngAnimate,则请保持应用程序配置不变,只需添加以下CSS:

.ng-hide.ng-hide-animate{
     display: none !important;
}

条件达成后,这将隐藏动画图标。

正如您所看到的,我们正在将 .ng-hide-animate 设置为 hidden。这就是延迟发生的原因,因为它等待动画完成。您可以像上面的示例那样将其隐藏,也可以将动画添加到隐藏事件中,因为类名暗示了这一点。


1
我有一个简单的页面,只有几个 ng-ifng-show,但是它看起来很慢。我移除了 ngAnimate,问题就解决了。谢谢! - Eamonn Gahan
1
这也解决了我遇到的问题... 你知道为什么有 ngAnimate 存在会导致缓慢的过渡吗? - Clark
我曾经遇到过同样的问题——移除ngAnimate解决了它。但这并不好……许多模块需要ngAnimate来实现酷炫的动画效果……该怎么办?ngAnimattias,你在哪里呢? :) - Spock
22
对于 ng-if,只需将 .ng-leave { display:none; } 添加到元素中即可完成操作(不需要使用 !important)。 - Joao

39

我曾经遇到过同样的问题,解决方法是使用ng-class和'hidden'类名来隐藏元素,而不是使用ng-if或ng-show/ng-hide。


1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Thiago Festa
1
你如何做到这一点? - jsmedmar
这快多了!为什么会这样? - Aron
1
我认为这只是因为使用ngAnimate会将进入/退出动画行为应用于使用ng-if/ng-show的元素,而对于ng-class表达式的更改则不会这样做。 - John Rix
@neimad 这个怎么做呢?在我的情况下,我需要使用 ng-if 来测试一个属性值是否为 null(因为它在等待 API 调用时会是 null 值),所以两个选择元素会短暂地显示。那么你是完全不使用 ng-if 吗?谢谢。 - Chris22

18

我在这里找到了一些解决方案,但对我来说最好的是覆盖 .ng-animate 类的样式:

.ng-animate.no-animate {
    transition: 0s none;
    -webkit-transition: 0s none;
    animation: 0s none;
    -webkit-animation: 0s none;
}

在HTML中:

<button ng-disabled="loading" class="button button-outline button-positive" type="submit">
    Log in 
    <span ng-if="loading" class="ion-refreshing no-animate"></span>
</button>

这是一个例子:http://jsfiddle.net/9krLr/27/

希望能对你有所帮助。


14

我曾经遇到过类似的问题,我使用了$scope.$evalAsync()来强制更新绑定。

这个方法非常有效。

避免使用$scope.$apply,因为它可能与已经运行的$digest阶段冲突。

if(selectedStatistics.length === 0 || selectedWorkgroups.length === 0){
    ctrl.isSaveDisabled = true;
    $scope.$evalAsync();
} else{
    ctrl.isSaveDisabled = false;
    $scope.$evalAsync();
}

适用于我。但它有没有任何缺点? - Sarah Tammam
1
我还没有遇到过这种情况。在异步操作的情况下非常方便。 - pixlboy
1
感谢您的有益回复 :) - Sarah Tammam
顺便说一下,这个延迟问题主要发生在本地环境中,很少在生产环境中出现 - 不知道为什么。 - Abdeali Chandanwala

1

最终我使用了Ruben的解决方案,但由于我无法为所有现有情况添加额外的类,所以我列出了我总是在没有动画的情况下使用的指令,期望立即呈现:

*[ng-hide],
*[ng-show],
*[ng-if],
*[ng-switch-when],
*[ng-switch-default] {
  transition: 0s none;
  -webkit-transition: 0s none;
  animation: 0s none;
  -webkit-animation: 0s none;
}

1
在Angular版本1.5.x中,在条件更改后添加$scope.$apply()可以完成工作。以下是一个示例函数。
$scope.addSample = function(PDF)
        {
            var validTypes ="application/pdf";
            if(PDF.type == validTypes)
            {
                //checking if the type is Pdf and only pdf
                $scope.samplePDF= PDF.files[0];
                $scope.validError = false;
                $scope.$apply();
            }

            else
            {
                 $scope.validError = true;
                 $scope.samplePDF= null;
                 $scope.$apply();
            }


        }

1
我在使用时遇到了相同的问题。
<div *ngIf='shouldShow'>
    <!-- Rest of DIV content here -->
</div>

在我的情况下,我通过添加一个类来解决这个问题:
.hidden {
  display: none;
}

然后有条件地添加类,而不是使用*ngIf

<div [ngClass]="{'hidden': !shouldShow}">
    <!-- Rest of DIV content here -->
</div>

如果总是这样使用,我会考虑将shouldShow重命名为shouldHide(并否定分配给它的逻辑),以便可以将其用作shouldHide而不是!shouldShow
如果您在DIV的现有类中使用了display: flex,那么该显示属性可能会优先于display:hidden。一个简单的解决方法是改用display: none !important,但通常有更好的解决方案来确保其他方式的优先级。这里有一篇关于替代方案的好文章

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