滚动事件AngularJS后在控制器中执行功能

时间:2013-12-26 20:50:01

标签: javascript angularjs

假设我有一个堆叠的文章:

<div ng-repeat="article in articles">
  <h1> {{article.title}} </h1>
  <p> {{article.body}} </p>
</div>

滚动浏览每篇文章时:

<div scroll="atNewArticle(article)" ng-repeat="article in articles">
  ...
</div>

我想执行一个函数:

.controller('AppCtrl', ['$scope', function($scope) {
  $scope.atNewArticle = function(){
    console.log(article);
  }
}])

我很难找到正确的方法,因为我不确定是否应该将滚动事件绑定到窗口或检测指令元素本身的偏移量。

这是我到目前为止所尝试的内容: http://jsfiddle.net/6VFJs/1/

3 个答案:

答案 0 :(得分:21)

有些事情可能是一个好主意(取决于您的确切用例)。首先,一些非Angular特定的:

  • 对scroll事件使用“debounced”版本的侦听器,以便该函数仅在用户停止滚动后才执行。您可以使用lodash / underscore库。

    var debounced = _.debounce(function() { .... }, 500); // Executes 500ms after last call of the debounced function.
    angular.element($document).on('scroll', debounced);
    
  • 使用库来确定任何元素的位置/可见性。 verge.js是我为此找到的一个小型轻量级库。使用它的一种方法是:

    var visible = verge.inViewport(element);
    

    但是,根据您想要将其视为“可见”的内容,您可能需要更改此内容。

  • 跟踪每个事件中可见/不可见的内容(因为您有一个“atNewArticle”功能,这表示您只希望在项目进入视图时调用它)。因此,您需要创建一个可见元素数组,并在滚动时对其进行测试。

    var index = visibleElements.indexOf(scope.scrollItem);
    

Angular特定点:

  • 将2个选项传递给指令。 1)新项目进入视图时的回调函数,以及2)文章项目本身,因此可以将其传递回回调。

    scope: {
         scroll: '&',
         scrollItem: '='
    }
    

    这些可以用作:

    <div ng-repeat="article in articles" class="block" scroll="atNewArticle(item)" scroll-item="article">
    

    这为指令的范围提供了变量scrollItem和函数scroll。所以该指令可以在适当的时候调用:

    scope.scroll({item:scope.scrollItem});
    

    你应该注意这个的语法:它是一个关键对象图。

您可以在http://jsfiddle.net/Pb8t4/4/

看到这一切

编辑:更新了包含对scope.$apply的调用的jsfiddle的链接,以便Angular正确注意到任何更改。

答案 1 :(得分:6)

您可以找到有用的 this 示例。

我的想法是使用:滚动绑定if语句过滤scope.$apply(attrs.scroll);调用

答案 2 :(得分:2)

您应该将scroll事件绑定到document,因为document是滚动的元素。然后,您可以检测文档的scrollTop并与重复项的偏移进行比较。

JSFiddle演示:http://jsfiddle.net/daiweilu/nzBS5/2/

我只使用jQuery和Angular 1.2.6。基本上我测试了ng-repeat项目的顶部边框与窗口顶部边框。如果项目开始离开窗口,则ng-repeat项目上的功能执行一次。如果物品返回并再次离开,则会再次触发该功能。

HTML

<div ng-controller="MyCtrl" scrollable-container>
    <div ng-repeat="article in articles" class="block" scrollable-item="atNewArticle(article)">
        <h1>{{article.title}}</h1>
        <p>{{article.body}}</p>
    </div>
</div>

JS     var app = angular.module('myApp',[]);

app.directive('scrollableContainer', function($window, $document) {
    return {
        link: function(scope, element, attrs) {
            angular.element($document).on('scroll', function() {
                var children = element.children();
                var $leftChild;
                for (var i = 0; i < children.length; i++) {
                    var $child = $(children[i]);
                    var childTop = $child.offset().top;
                    var docScrollTop = $document.scrollTop();
                    var scope = $child.scope();
                    if (childTop - docScrollTop < 0) {
                        if (!scope._left) {
                            scope._left = true;
                            $leftChild = $child;
                        }
                    } else {
                        delete scope._left;
                    }
                }
                if ($leftChild) {
                    $leftChild.scope().$eval( $leftChild.attr('scrollable-item') );
                }
            });
        }
    };
});


function MyCtrl($scope) {

    $scope.articles = [
        {title:'article1',body:'body of article1'},   
        {title:'article2',body:'body of article2'},
        {title:'article3',body:'body of article3'}
    ];

    $scope.atNewArticle = function (article) {
        //i only execute when transitioning back and forth between articles
        console.log(article);
    };
}