AngularJS - 指令渲染完成后如何查询 DOM

Posted

技术标签:

【中文标题】AngularJS - 指令渲染完成后如何查询 DOM【英文标题】:AngularJS - How to query the DOM when directive rendering is complete 【发布时间】:2012-12-23 12:38:40 【问题描述】:

我正在尝试使用 AngularJS 指令实现自定义滚动窗格组件。在下面jsfiddle example我有一个基本原型的例子。

这是我的想法的架构:

这是指令代码:

    myApp.directive('lpScrollPane', function factory() 
    return 
        restrict: 'A',
        replace: true,
        transclude: true,
        template: '<div class="scrollPaneWrapper"><div class="scrollPane" ng-transclude></div><div class="thumbTrack" ></div></div>',
        compile: function (tElement, tAttrs) 
            var minHeight = 30;
            return function (scope, iElement, iAttrs) 
                var thumbTrack = angular.element(iElement.children()[1]);

                scope.onScrollHeight = function () 
                    console.log(iElement.children()[0].scrollHeight);

                    var H1 = iElement[0].offsetHeight;
                    var H2 = iElement.children()[0].scrollHeight;
                    if (H2 > H1) 
                        var trackHeight = Math.round(minHeight + (H1 - minHeight) * (1 - Math.pow((H2 - H1) / H2, 0.8)));
                        thumbTrack.css(
                            display: "block",
                            height: trackHeight + "px"
                        );
                        console.log(H2, H1, trackHeight);
                     else 
                        thumbTrack.css(
                            display: "none"
                        );
                    
                ;

                scope.$watch(function () 
                    scope.onScrollHeight();
                    //setTimeout(scope.onScrollHeight, 100)
                );


            
        
    ;
);

基本上有 2 次潜水,1 次隐藏溢出,1 次带有溢出滚动,另一个 div 模拟拇指跟踪器。

我的目标是监控 scrollHeight 属性,然后相应地更改跟踪器高度。问题是 $watch 在渲染 DOM 之前被触发,因此在显示和计算跟踪器时会出现延迟。现在我在 watch 函数上使用了 setTimeout,它工作正常(取消注释第 35 行和第 34 行以查看它的实际效果)。

正确的方法是什么?

【问题讨论】:

【参考方案1】:

见is there a post render callback for Angular JS directive?

很遗憾,无法确定渲染何时完成(例如,没有事件)。使用 $timeout 似乎是最好的解决方法。

在上面的链接中,@Nik 在评论中提到他正在检查$('tr').length &gt; 3,以针对他的特定场景来确定渲染何时完成。也许您可以定期检查 DOM 中的某些内容以确定渲染是否完成。

【讨论】:

谢谢,我会调查的【参考方案2】:

两个观察结果:

你不需要compile imho,而是link 函数 你应该等到元素准备好,而不是使用超时

所以:

myApp.directive('lpScrollPane', function factory() 
  return 
    restrict: 'A',
    replace: true,
    transclude: true,
    template: '<div class="scrollPaneWrapper"><div class="scrollPane" ng-transclude></div><div class="thumbTrack" ></div></div>',
    link: function (scope, iElement, iAttrs) 
      var minHeight = 30;
      var thumbTrack = angular.element(iElement.children()[1]);

      scope.onScrollHeight = function () 
        console.log(iElement.children()[0].scrollHeight);

        var H1 = iElement[0].offsetHeight;
        var H2 = iElement.children()[0].scrollHeight;
        if (H2 > H1) 
          var trackHeight = Math.round(minHeight + (H1 - minHeight) * (1 - Math.pow((H2 - H1) / H2, 0.8)));
          thumbTrack.css(
            display: "block",
            height: trackHeight + "px"
          );
          console.log(H2, H1, trackHeight);
         else 
          thumbTrack.css(
            display: "none"
          );
        
      ;

      iElement.ready(function ()   
         scope.$watch(function () 
           scope.onScrollHeight();
         );
      );        
    
  ;
);

见jsFiddle。

编辑:

因为2张图片超过1000字,这里有两张截图:

【讨论】:

感谢您的回复,但正如您在更新的小提琴 (jsfiddle.net/neuTA/136) 中看到的那样,它并没有解决问题。可以看到thumbTrack的创建延迟了一个$digest step(等到底部内容溢出) 蓝条从值溢出的那一刻开始出现。这不是应该的样子吗? 你看过更新的小提琴了吗? (jsfiddle.net/neuTA/136) 因为我看到的不是这个,所以蓝条出现在第二行overflow 你的意思是开头的(半)蓝条出现半秒吗? 不,这只是一个 CSS 问题(已修复 jsfiddle.net/neuTA/139),我看到正常的溢出滚动,然后当插入另一行时出现蓝条(我使用 chrome)

以上是关于AngularJS - 指令渲染完成后如何查询 DOM的主要内容,如果未能解决你的问题,请参考以下文章

dom 完成渲染后如何运行指令?

angularjs如何在视图渲染结束之后,或者render之后执行指令中的link方法呢?

AngularJS加载完成后发送事件

AngularJS:AngularJS 渲染模板后如何运行附加代码?

Angularjs[22] - 内置渲染指令

Angular 4 - 如何仅在其父级完全渲染后运行指令方法