【问题标题】:ng-scrollbar is not working with ng-repeatng-scrollbar 不适用于 ng-repeat
【发布时间】:2014-10-10 15:17:15
【问题描述】:

在我的应用程序中,我想为 div 使用自定义滚动条。所以我使用了 ng-scrollbar,它可以很好地处理静态数据。但是,每当我使用 ng-repeat 获取数据时,它就无法正常工作。请在这方面帮助我。提前致谢。

myFile.html

<style>
  .scrollme {
    max-height: 300px;
   }
</style>

<div ng-app="myapp">
  <div class="container" ng-controller="myctrl">

    <button class="btn btn-info" ng-click="add();">add</button>
    <button class="btn btn-warning" ng-click="remove();">remove</button>

    <div class="well" >
      <div class="scrollme" ng-scrollbar bottom rebuild-on="rebuild:me">
        <h1>Scroll me down!</h1>
        <p ng-repeat="mi in me">{{mi.name}}</p>
      </div>
    </div>
  </div>
</div>

myCtrl.js

var myapp = angular.module('myapp', ["ngScrollbar"]);
myapp.controller('myctrl', function ($scope) {
    $scope.me = [];
    for(var i=1;i<=20;i++){
        $scope.me.push({"name":i});
    }
    var a = $scope.me.length;
    $scope.add = function(){        
    $scope.me.push({"name":$scope.me.length+1});
    $scope.$broadcast('rebuild:me');
    }
    $scope.remove = function(){
        $scope.me.pop();
    }
});

【问题讨论】:

  • 单击添加按钮后滚动条是否起作用?两件事:您可能希望将rebuild:me 事件添加到scope.remove,因为您告诉滚动条在添加时进行更新,因此在删除时也进行更新是有意义的。您可能还想在控制器末尾添加事件广播,以便它在初始渲染时触发,而无需单击 add()。可能必须进入 $timeout(fund(){}, 0) 以允许 ngRepeat 渲染,idk。

标签: angularjs angularjs-ng-repeat


【解决方案1】:

尝试将broadcast 调用添加到控制器的末尾,以便在控制器加载时触发。如果这不起作用,请尝试添加:

$timeout(function () {
    $scope.$broadcast('rebuild:me');
}, 0);
// 0 optional, without it the time is assumed 0 which means next digest loop.

在控制器代码的末尾,而不是在 add 函数中。如果这可行,但之前的方法不起作用,则意味着 ngRepeat 没有及时完成呈现它的动态内容,以便 ngScrollbar 正确更新。

更新:通常,您可能还必须在超时时将广播包装在 add() 函数中。我这样说的原因是我怀疑发生了什么是您将数据添加到范围变量,然后在同一个函数调用中广播所有内容。可能发生的情况是,在 ngRepeat 看到更新的范围数据并添加其额外的 DOM 元素之前,广播事件被捕获并重新计算滚动条。顺便说一句,如果你想在 add() 上重新计算滚动条,那么你也想在 remove() 上这样做。

所以你的 add 函数会变成:

$scope.add = function(){        
    $scope.me.push({"name":$scope.me.length+1});
    // wait until next digest loop to send event, this way ngRepeat has enough time to update(?)
    $timeout(function () {
        $scope.$broadcast('rebuild:me');
    });
}

【讨论】:

  • 这也不起作用。我使用 $scope.$broadcast('buildScrollbar'); 而不是 $scope.$broadcast('rebuild:me'); 。我删除了 buildScrollbar() 的调用ngScrollbar.js 中的函数。它在开始时完美显示,但是当我单击添加按钮时,我的 div 高度正在减小。 4 到 5 次点击后,div 高度完全消失了。
【解决方案2】:

请尝试 ng-scroll... 另一个插件,但无需手动调整。 提到:

AngularJS with ng-scroll and ng-repeat

【讨论】:

    【解决方案3】:

    如果你使用 jQuery,你可以试试 jQuery Scrollbar - 它有更多 options 和完全可定制的 CSS。

    ng-repeat 的例子是here

    JavaScript

    var demoApp = angular.module('demoApp', ['jQueryScrollbar']);
    
    demoApp.controller('SimpleController', function($scope){
    
        $scope.me = [];
        for(var i=1;i<=20;i++){
            $scope.me.push({"name":i});
        }
    
        $scope.add = function(){
            $scope.me.push({"name":$scope.me.length+1});
        }
        $scope.remove = function(){
            $scope.me.pop();
        }
    
        $scope.jqueryScrollbarOptions = {
            "onUpdate":function(container){
                setTimeout(function(){
                    // scroll to bottom. timeout required as scrollbar restores
                    // init scroll positions after calculations
                    container.scrollTop(container.prop("scrollHeight"));
                }, 10);
    
    
            }
        };
    });
    

    HTML

    <div data-ng-app="demoApp">
        <div data-ng-controller="SimpleController">
            <button class="btn btn-info" ng-click="add();">add</button>
            <button class="btn btn-warning" ng-click="remove();">remove</button>
            <div class="scrollbar-dynamic" data-jquery-scrollbar="jqueryScrollbarOptions">
                <h1>Scroll me down!</h1>
                <p ng-repeat="mi in me">{{mi.name}}</p>
            </div>
        </div>
    </div>
    

    CSS

    .scrollbar-dynamic {
        border: 1px solid #FCC;
        max-height: 300px;
        overflow: auto;
    }
    

    【讨论】:

      【解决方案4】:

      这可能有点晚了。

      问题是即使您已将内容添加到范围变量,angular 还没有完成将 p 标签添加到您的 DOM。如果您尝试像

      这样的简单控制台日志
      console.log($('.well').find('p').length);
      

      将内容推送到$scope.me后,你就会明白发生了什么。 (至少需要 jQuery 来调试)

      解决方案远比你想象的复杂。

      第 1 步:

      ng-controller 添加到您的ng-repeat(是的。允许)

      <p ng-repeat="mi in me" ng-controller="loopController">{{mi.name}}</p>
      

      第 2 步:定义loopController

      demoApp.controller('loopController', function($scope) {
          $scope.$watch('$last', function(new_val) {
              new_val && $scope.$emit('loopLoaded', $scope.$index);
          });
      });
      

      每当ng-repeat 操作 DOM 时都会触发此控制器功能。我正在观看$last,它是ng-repeat 的范围变量。每当ng-repeat 加载 DOM 中的最后一个元素时,这将设置为 true。当$last 设置为true 时,我会发出一个事件loopLoaded。由于您使用循环将值推送到$scope.me,因此每次推送都会触发此事件。


      第 3 步:事件处理

      在您的 SimpleController 中(不再简单,是吗?)

      $scope.$on('loopLoaded', function(evt, index) {
          if (index == $scope.me.length-1) {
              $scope.$broadcast('rebuild:me');
          }
      });
      

      加载所有 p 元素后,发送到事件的index 将等于$scope.me.length-1。所以你叫滚动重建。就是这样。

      这是我使用的参考资料 - AngularJS - Manipulating the DOM after ng-repeat is finished

      【讨论】:

      • 这过于复杂但本质上是最好的解决方案。当您 $watch($last) 函数参数不是一个值时,它是一个“isLast”值,它提供 false 直到到达最后一项时它为真。这意味着您可以在那里发出“rebuild:me”。无需回调主控制器并测试长度。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-18
      • 2018-11-05
      • 1970-01-01
      • 2018-07-29
      • 1970-01-01
      相关资源
      最近更新 更多