保留AngularJS中路线变化的滚动位置?

48 javascript angularjs

示例应用程序:http://angular.github.com/angular-phonecat/step-11/app/#/phones

如果您选择最后一部手机"摩托罗拉魅力",它会显示手机的详细信息.当您在浏览器上导航回来时,它会重新加载数据,滚动位于顶部.

当导航回来时,自动滚动到哪里的最佳方法是什么?而且,为什么angular会重新加载数据?

我的计算机上有相同的"angular-phonecat"样本,我添加了一个无限滚动,滚动时会加载更多数据.所以我真的不希望用户再次重新加载50多个项目或向下滚动30秒.

Jos*_*ter 31

我在这里有一个小提琴,展示了如何在详细视图后恢复列表视图中的滚动位置; 尚未封装在指令中,正在努力......

http://jsfiddle.net/BkXyQ/6/

$scope.scrollPos = {}; // scroll position of each view

$(window).on('scroll', function() {
    if ($scope.okSaveScroll) { // false between $routeChangeStart and $routeChangeSuccess
        $scope.scrollPos[$location.path()] = $(window).scrollTop();
        //console.log($scope.scrollPos);
    }
});

$scope.scrollClear = function(path) {
    $scope.scrollPos[path] = 0;
}

$scope.$on('$routeChangeStart', function() {
    $scope.okSaveScroll = false;
});

$scope.$on('$routeChangeSuccess', function() {
    $timeout(function() { // wait for DOM, then restore scroll position
        $(window).scrollTop($scope.scrollPos[$location.path()] ? $scope.scrollPos[$location.path()] : 0);
        $scope.okSaveScroll = true;
    }, 0);
});
Run Code Online (Sandbox Code Playgroud)

小提琴还显示在"ListCtrl"之外获取列表一次.


br2*_*000 17

下面是keep-scroll-pos指令的另一个版本.这个版本

  • 记住$ routeProvider定义的每个templateUrl的滚动位置.

  • 尊重哈希标签,例如#/ home#section-2,将滚动到#section-2而不是之前的滚动位置.

  • 易于使用,因为它是独立的,并在内部存储滚动位置.

html使用示例:

<div ng-view keep-scroll-pos></div>
Run Code Online (Sandbox Code Playgroud)

keepScrollPos指令的代码如下:

"use strict";

angular.module("myApp.directives", [])

.directive("keepScrollPos", function($route, $window, $timeout, $location, $anchorScroll) {

    // cache scroll position of each route's templateUrl
    var scrollPosCache = {};

    // compile function
    return function(scope, element, attrs) {

        scope.$on('$routeChangeStart', function() {
            // store scroll position for the current view
            if ($route.current) {
                scrollPosCache[$route.current.loadedTemplateUrl] = [ $window.pageXOffset, $window.pageYOffset ];
            }
        });

        scope.$on('$routeChangeSuccess', function() {
            // if hash is specified explicitly, it trumps previously stored scroll position
            if ($location.hash()) {
                $anchorScroll();

            // else get previous scroll position; if none, scroll to the top of the page
            } else {
                var prevScrollPos = scrollPosCache[$route.current.loadedTemplateUrl] || [ 0, 0 ];
                $timeout(function() {
                    $window.scrollTo(prevScrollPos[0], prevScrollPos[1]);
                }, 0);
            }
        });
    }
});

要忽略先前存储的滚动位置,并强制滚动到顶部,请使用伪哈希标记:#top,例如,href =" #/ home #top ".

或者,如果您希望始终滚动到顶部,请使用内置的ng-view autoscroll选项:

<div ng-view autoscroll></div>
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案最适合我.我使用ui路由器进行路由,所以我用$ state替换了所有出现的$ route.否则,不需要进行其他更改.我也喜欢如何使用$ window和$ anchorScroll而不是在其他一些建议的答案中使用的jquery依赖的$(窗口). (4认同)

emp*_*emp 9

我使用了@Joseph Oster的解决方案来创建一个指令.我也冒昧地更新了使用的答案:

  • $ locationChangeStart
  • $ locationChangeSuccess

因为其他事件已经过时了.

小提琴在这里:http://jsfiddle.net/empie/p5pn3rvL/

指令来源:

angular.module('myapp', ['ngRoute'])
    .directive('autoScroll', function ($document, $timeout, $location) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            scope.okSaveScroll = true;

            scope.scrollPos = {};

            $document.bind('scroll', function () {
                if (scope.okSaveScroll) {
                    scope.scrollPos[$location.path()] = $(window).scrollTop();
                }
            });

            scope.scrollClear = function (path) {
                scope.scrollPos[path] = 0;
            };

            scope.$on('$locationChangeSuccess', function (route) {
                $timeout(function () {
                    $(window).scrollTop(scope.scrollPos[$location.path()] ? scope.scrollPos[$location.path()] : 0);
                    scope.okSaveScroll = true;
                }, 0);
            });

            scope.$on('$locationChangeStart', function (event) {
                scope.okSaveScroll = false;
            });
        }
    };
})
Run Code Online (Sandbox Code Playgroud)


asg*_*oth 6

我之前没有使用它,但angular有一个$ anchorScroll服务.至于重新加载数据,您可以使用$ cacheFactory缓存它,或将数据存储在更高的范围内.


Ant*_*ton 5

我创建了一个适用于窗口滚动的指令(它可以更新为可以处理任何元素)

HTML用法

<div ng-keep-scroll="service.scrollY">
<!-- list of scrolling things here -->
</div>
Run Code Online (Sandbox Code Playgroud)

其中"service.scrollY"必须是服务中的变量.服务保留其状态和值,每次加载和清除其值时都会重新创建控制器,因此您无法使用它们来存储持久数据.控制器有一个指向服务的范围变量.

指令js

app.directive('ngKeepScroll', function ($timeout) {
    return function (scope, element, attrs) {

        //load scroll position after everything has rendered
        $timeout(function () {
            var scrollY = parseInt(scope.$eval(attrs.ngKeepScroll));
            $(window).scrollTop(scrollY ? scrollY : 0);
        }, 0);

        //save scroll position on change
        scope.$on("$routeChangeStart", function () {
            scope.$eval(attrs.ngKeepScroll + " = " + $(window).scrollTop());
        });
    }
});
Run Code Online (Sandbox Code Playgroud)