当前位置: 首页 > 面试题库 >

AngularJS-在ng-repeat完成后操作DOM

富勇军
2023-03-14
问题内容

在遍历数据后,我遇到一些有关DOM操作的问题。

我们有一个与数据绑定并且可以正常工作的jQuery滑块插件,但是当使用时ng- repeat,我们必须将其初始化包装起来$timeout以使其起作用—现在甚至不起作用。

我认为使用$timeout是不可靠的,这将导致错误的修复。在jQuery中,我可以使用$(document).ready()-这很可靠,但是使用angular.element(document).ready()似乎也不起作用。

调用了Slider指令,但由于没有将图像加载到DOM中而无法获得滑块中图像的高度-导致滑块的计算高度为0。

我现在感到非常沮丧-必须有一种方法来ng-repeat循环处理数据(例如)之后的DOM 。

滑块的初始化如下:

var sliderLoad = function () {
    $timeout(function () {
        var setHeight = elem.find('.slide:eq(0)').outerHeight(true);
        elem.css({
            height: setHeight
        });
    }, 1000);
    // Show the slider nav buttons
    elem.parent().find('.direction-nav').show();
};

……这是一个 复制演示


问题答案:

我们要确保所有图像都已加载,因此让我们为此编写一个指令:

app.directive('loadDispatcher', function() {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            element.bind('load', function() {
                scope.$emit('$imageLoaded');
            });
        }
    };
})

…并将其附加到ng-src‘d元素

<img class="thumb-recipe" ng-src="{{ object.tile_url }}" load-dispatcher/>

现在,我们可以比较模型捕获的事件数量,并根据需要进行操作:

var loadCount = 0;
scope.$on('$imageLoaded', function () {
    if (loadCount++ === scope.videos.objects.length - 1) {
        _initSlider(); // act!
    }
});

解耦(演示)

这有点令人不安,因为它不遵守Demeter律
-任何监视$imageLoaded事件的指令都必须知道模型(scope.videos.objects.length)。

我们可以通过查找加载多少图像而无需显式寻址模型来防止这种耦合。假设事件将在中处理ng-repeat

  1. 确保ng-repeat已完成,并使用项目计数触发事件。我们可以通过附加一个控制器来实现此目的,即仅监视$last财产。一旦找到它(具有真实值),我们将触发一个事件来通知它:
        .controller('LoopWatchCtrl', function($scope) {
        $scope.$watch('$last', function(newVal, oldVal) {
            newVal && $scope.$emit('$repeatFinished', $scope.$index);
        });
    })


        <div ng-repeat="object in videos.objects" ng-controller="LoopWatchCtrl">
  1. 现在,捕获事件并相应地激活滑块初始化:
        var loadCount = 0,
        lastIndex = 0;

    scope.$on('$repeatFinished', function(event, data) {
        lastIndex = data;
    });

    scope.$on('$imageLoaded', function() {
        if (lastIndex && loadCount++ === lastIndex) {
            _initSlider(element); // this is defined where-ever
        }
    });

在那里,现在我们的指令不必了解模型。但是,这有点麻烦,现在我们必须将指令 控制器绑定在一起。

折叠(演示)

让我们将整个shabang提取到一个指令中:

    app.directive('imageLoadWatcher', function($rootScope) {
        return {
            restrict: 'A',
            link: function(scope, element, attrs) {
                if (typeof $rootScope.loadCounter === 'undefined') {
                    $rootScope.loadCounter = 0;
                }
                element.find('img').bind('load', function() {
                    scope.$emit('$imageLoaded', $rootScope.loadCounter++);
                });
            },
            controller: function($scope) {
                $scope.$parent.$on('$imageLoaded', function(event, data) {
                    if ($scope.$last && $scope.$index === $rootScope.loadCounter - 1) {
                        $scope.$emit('$allImagesLoaded');
                        delete $rootScope.loadCounter;
                    }
                });
            }
        };
    });

…将应用于ng-repeated元素:

    <div ng-repeat="object in videos.objects" class="slide" image-load-watcher>

现在我们可以简单地$allImagesLoaded在滑块中观看例如:

    scope.$on('$allImagesLoaded', function() {
        _initSlider(element);
    });

将其概括(如果需要)(演示)

我们可以再次对其进行分解,并在整个应用程序中应用此方法,以对 任何 ng-repeat完成或ng-src负载使用事件分发,这并非总是必要的(
1 ),但可能非常有用。让我们看看如何:

  1. 装饰ng-src指令,以便在加载图像时发送事件:
        app.config(function($provide) {
        $provide.decorator('ngSrcDirective', function($delegate) {
            var directive = $delegate[0],
                link = directive.link;
            directive.compile = function() {
                return function(scope, element, attrs) {
                    link.apply(this, arguments);
                    element.bind('load', function() {
                        scope.$emit('$imageLoaded');
                    });
                };
            };

            return $delegate;
        });
        // ...
    });
  1. 装饰ng-repeat完成时通知:
        app.config(function($provide) {
        // ...
        $provide.decorator('ngRepeatDirective', function($delegate) {
            var directive = $delegate[0],
                link = directive.link;
            directive.compile = function() {
                return function(scope, element, attrs) {
                    link.apply(this, arguments);
                    scope.$watch('$$childTail.$last', function(newVal, oldVal) {
                        newVal && scope.$emit('$repeatFinished');
                    });
                };
            };

            return $delegate;
        });
    });
  1. 现在可以在任何地方捕获事件,例如在您的滑块指令中:
        var repeatFinished = false;
    var loadCount = 0;

    scope.$on('$repeatFinished', function() {
        repeatFinished = true;
    });

    scope.$on('$imageLoaded', function () {
        if (repeatFinished && 
                    loadCount++ === scope.videos.objects.length - 1) {
            _initSlider(); // this is defined where-ever
        }
    });

当我们回到第一个问题时,这似乎无法达到目的,但它可能非常强大。还有-看,妈妈,没有新指令!

    <div ng-repeat="object in videos.objects" class="slide">
        <img class="thumb-recipe" ng-src="{{ object.tile_url }}"/>
    </div>

(演示)

TL;DR, just gimme tha demo!!!

1 。必须仔细考虑修饰,因为结果将在整个应用程序中加载的每个图像上发送一个事件。

link1.3.x版开始,将无法覆盖该功能。



 类似资料:
  • 问题内容: 我试图实现的基本上是“重复完成渲染”处理程序。我能够检测到何时完成,但是我不知道如何从中触发功能。 检查小提琴:http : //jsfiddle.net/paulocoelho/BsMqq/3/ JS 的HTML 答 :从finishmove的工作提琴:http : //jsfiddle.net/paulocoelho/BsMqq/4/ 问题答案: 请注意,我没有使用,而是将其包装在

  • 问题内容: 我想用表调用一些针对div的jQuery函数。该表填充了。 当我打电话时 我没有结果。 也 没有帮助。 ng重复填充完成后,有什么方法可以执行功能?我已经阅读了有关使用custom的建议,但是我不知道如何在ng- repeat和div中使用它。 问题答案: 确实,您应该使用指令,并且ng- Repeat循环的末尾没有事件关联(因为每个元素都是单独构造的,并且具有自己的事件)。但是a)您

  • 问题内容: 我想用表调用一些针对div的jQuery函数。该表中填充了。 当我打电话时 我没有结果也 没有帮助。 ng重复填充完成后,有什么方法可以执行功能?我已经阅读了有关使用custom的建议,但是我不知道如何在ng-repeat和div中使用它。 问题答案: 确实,您应该使用指令,并且没有与ng-Repeat循环的结尾相关的事件(因为每个元素都是单独构造的,并且具有自己的事件)。但是a)使用

  • 问题内容: 嗨,我有一个简单的ng-repeat-start和end用例,并且工作正常,当我想添加一个内部ng-repeat时出现了问题。这是我的代码 内部ng-repeat到td元素中不起作用,在检查html源代码时看到ngRepeat注​​释,但未创建td元素。 我的丑陋的解决方法(假设我知道该向量的大小)是: 问题答案: 从那时起,我不确定是否使用角度1.1.6,并且在1.1.5或1.0.7

  • 问题内容: 我们有一个大型模型,ng- repeat需要几秒钟的时间才能将模型中的所有项目绑定到表单。我们想展示一个微调器,它正在发生。绑定完成时是否会触发某些事件,以便我们知道何时隐藏微调器? 问题答案: Plunkr:http://plnkr.co/edit/GzzTW4?p = preview 使用如果您使用的是1.2使用的微调 在指令中,使用$ last确定渲染是否完成,然后更改定义了ng

  • 问题内容: 我使用ng-repeat在表中动态添加来自数组的行。 现在,我想获取每行所有总和的总和(group.sum * group.perc / 100.0)。我需要一个变量,因为我需要此值进行进一步的计算。谢谢 的HTML 脚本 问题答案: 创建一个过滤器: 使用$ filter服务: 在您的HTML中使用它: