AngularJS:状态更改后自动滚动到锚点

时间:2015-10-15 17:13:52

标签: angularjs angular-ui-router autoscroll

我希望用户点击页面上的链接,这将触发stateChange并将其引导到新状态。我想要实现的是当状态完成加载后,然后滚动到上一页上链接指定的页面上的锚点。

要做到这一点我正在使用$ stateParam通过ui-sref这样的组合:

<a ui-sref="stateParent.stateChild({id: 'practiceParam'})">goToPage</a>

然后当到达页面时,有一个div坐在上面,附带一个指令,激活$ viewContentLoaded,所以DOM被渲染,我可以搜索一个ID。 HTML div看起来像这样:

<div scroll-after-load ></div>

我的滚动指令如下:

angular.module( 'app' ).directive('scrollAfterLoad', function() {
  return {
    restrict: 'A',
    link: function(scope, $elm, attrs, $stateParams) {
        scope.$on('$viewContentLoaded', function() {
            console.log('scrollAfterLoad Directive Loaded, $stateParams are: ', $stateParams );
            var idToScroll = attrs.href;
            var $target;
            if (idToScroll) {
                $target = $(idToScroll);
                // the -50 accounts for the top navbar which is fixed on the page and removed from pageflow
                $("html,body").animate({scrollTop: $target.offset().top - 50}, "slow");
            }
        });
    }
  };
});

我没有为在div上设置href而烦恼,因为我无法访问传递的参数,我是否错误地访问了它?我也尝试使用更标准的state.go()传递stateParam,但我的结果仍为null。

一旦我可以传递一个状态参数,想法只是将一个href添加到新加载的页面上注入div的params,并使用与我传递的参数匹配的ID自动滚动到该页面上的另一个div。

同样是旁注,在我的ui-view上我将autoscroll设置为true,因此页面自动加载到顶部,我喜欢这种行为,这就是我需要状态在scoll激活之前完成加载的原因。

2 个答案:

答案 0 :(得分:2)

使用angular-scroll你可以这样做:

将您的scroll target id状态参数传递给子状态控制器,然后使用scrollToAnimated(element)滚动到该元素。

如果您希望将其重复使用,您可以创建该控制器的工厂并将其注入解决子状态。这应该也可以,但我没有测试过。

如果您处于子状态并且再次单击状态更改链接,则可能需要重新触发滚动。这就是为什么我添加了重新加载当前状态的方法checkState,如果我们处于子状态以重复滚动。

请查看下面的演示或此fiddle

我认为你的指令不起作用,因为你没有将href属性传递给你的指令。

您可以通过将href="targetId"传递到您的子控制器中targetId添加了$scope.targetId = $stateParams.id的指令来解决此问题。或者,如果您没有使用隔离范围,则可以直接访问targetId $scope

无论如何,我会这样做,就像我在演示中或在工厂里面的决心一样。

angular.module('demoApp', ['ui.router', 'duScroll'])
	.controller('MainControlller', MainController)
	.config(Config);

function MainController($scope, $state) {
	$scope.checkState = function() {
    	//console.log($state.current);
        if($state.current.name == 'parent.child') {
            //console.log('parent.child state');
        	// reload to retrigger scrolling again
           $state.reload();
        }
    };
}

function Config($urlRouterProvider, $stateProvider) {
	$urlRouterProvider.otherwise('/');
    
    $stateProvider
    	.state('parent', {
        	url: '/',
        	templateUrl: 'home.html'
    })
    	.state('parent.child', {
    	url: 'child/:id',
        templateUrl: 'child.html',
        controller: function($scope, $stateParams, $document) {
        	var scrollElement = angular
                .element(document.getElementById($stateParams.id));
            console.log(scrollElement);
            $document.scrollToElementAnimated(scrollElement);
        }
    });
               
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-scroll/0.7.3/angular-scroll.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.15/angular-ui-router.js"></script>
<div ng-app="demoApp" ng-controller="MainController">
    <script type="text/ng-template" id="home.html">
        <a ui-sref="parent.child({id: 'practiceParam'})" ng-click="checkState()">go to practice</a>
        <div ui-view=""></div>
    </script>
    <script type="text/ng-template" id="child.html">
        <!--<a href="#practiceParam" du-smooth-scroll="">scroll to practice</a>
        --><p>
            Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 
        </p><p>
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 
        </p><p>
Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.</p>
<p>
Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 
        </p>
        <p>
            Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 
        </p>
        <h1 id="practiceParam">practice</h1>
        <p>
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 
        </p><p>
Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.</p>
<p>
Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 
        </p>
        <a ui-sref="parent">back</a>
    </script>
    
    <div ui-view=""></div>
</div>

答案 1 :(得分:2)

您的问题是您正在尝试将$stateParams服务注入链接功能。但是,这种注射的正确位置是工厂方法,意味着指令的定义。工厂方法已在模块中注册 - 与您的scrollAfterLoad指令一样。有关详细信息,请查看AngularJS Dependency Injection

回到你的问题:如果你真的将$stateParams注入到你的指令的工厂方法中,意味着在顶部你将能够轻松访问参数。您的指令可能如下所示:

angular.module( 'app' ).directive('scrollAfterLoad', ['$stateParams', function($stateParams) {
  return {
    restrict: 'A',
    link: function(scope, $elm, attrs) {
        scope.$on('$viewContentLoaded', function() {
            console.log('scrollAfterLoad Directive Loaded, $stateParams are: ', $stateParams );
            var idToScroll = attrs.href;
            var $target;
            if (idToScroll) {
                $target = $(idToScroll);
                // the -50 accounts for the top navbar which is fixed on the page and removed from pageflow
                $("html,body").animate({scrollTop: $target.offset().top - 50}, "slow");
            }
        });
    }
  };
}]);

请注意,我已从链接功能中删除$stateParams并将其置于顶部。这样,服务将在链接功能中可用 - 实际上在整个指令中。

我在此Plunker中重现了您的方案。

相关问题