2

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

这是我的想法的架构: 在此处输入图像描述

这是指令代码:

    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 以查看它的运行情况)。

什么是正确的方法?

4

2 回答 2

5

看看Angular JS 指令是否有渲染后回调?

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

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

于 2013-01-09T17:37:22.710 回答
4

两个观察:

  • 你不需要恕我compile直言,但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多字,这里有两张截图: 最后一个仍然可见的元素被插入 第一个不可见的元素被插入

于 2013-01-09T13:20:59.107 回答