有人知道如何在AngularJS中很好地处理锚散列链接吗?

对于一个简单的faq页面,我有以下标记

<a href="#faq-1">Question 1</a>
<a href="#faq-2">Question 2</a>
<a href="#faq-3">Question 3</a>

<h3 id="faq-1">Question 1</h3>
<h3 id="faq-2">Question 2</h3>
<h3 id="fa1-3">Question 3</h3>

当点击上面的任何链接时,AngularJS会拦截并将我路由到一个完全不同的页面(在我的例子中,一个404页,因为没有路由匹配这些链接)。

我的第一个想法是创建一个匹配“/faq/:chapter”的路由,并在相应的控制器中检查$routeParams。然后使用jQuery向下滚动到它。

但是AngularJS又把我搞砸了,反正就是滚动到页面顶部。

有人在过去做过类似的事情并且知道一个好的解决方法吗?

编辑:切换到html5Mode应该解决我的问题,但我们有点必须支持IE8+无论如何,所以我担心这不是一个可接受的解决方案:/


当前回答

这可能是ngView的一个新属性,但我已经能够使用ngView autoscroll属性和'double-hashes'让它锚定哈希链接与angular-route一起工作。

ngView(见autoscroll)

(以下代码用于角钢带)

<!-- use the autoscroll attribute to scroll to hash on $viewContentLoaded -->    
<div ng-view="" autoscroll></div>

<!-- A.href link for bs-scrollspy from angular-strap -->
<!-- A.ngHref for autoscroll on current route without a location change -->
<ul class="nav bs-sidenav">
  <li data-target="#main-html5"><a href="#main-html5" ng-href="##main-html5">HTML5</a></li>
  <li data-target="#main-angular"><a href="#main-angular" ng-href="##main-angular" >Angular</a></li>
  <li data-target="#main-karma"><a href="#main-karma" ng-href="##main-karma">Karma</a></li>
</ul>

其他回答

尝试为angular路由设置一个哈希前缀$locationProvider.hashPrefix('!')

完整的例子:

angular.module('app', [])
  .config(['$routeProvider', '$locationProvider', 
    function($routeProvider, $locationProvider){
      $routeProvider.when( ... );
      $locationProvider.hashPrefix('!');
    }
  ])

这是我使用一个指令的解决方案,它看起来更像angular,因为我们处理的是DOM:

这里的Plnkr

github

CODE

angular.module('app', [])
.directive('scrollTo', function ($location, $anchorScroll) {
  return function(scope, element, attrs) {

    element.bind('click', function(event) {
        event.stopPropagation();
        var off = scope.$on('$locationChangeStart', function(ev) {
            off();
            ev.preventDefault();
        });
        var location = attrs.scrollTo;
        $location.hash(location);
        $anchorScroll();
    });

  };
});

HTML

<ul>
  <li><a href="" scroll-to="section1">Section 1</a></li>
  <li><a href="" scroll-to="section2">Section 2</a></li>
</ul>

<h1 id="section1">Hi, I'm section 1</h1>
<p>
Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora quaeritis. 
 Summus brains sit​​, morbo vel maleficia? De apocalypsi gorger omero undead survivor dictum mauris. 
Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil vultus comedat cerebella viventium. 
Nescio brains an Undead zombies. Sicut malus putrid voodoo horror. Nigh tofth eliv ingdead.
</p>

<h1 id="section2">I'm totally section 2</h1>
<p>
Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora quaeritis. 
 Summus brains sit​​, morbo vel maleficia? De apocalypsi gorger omero undead survivor dictum mauris. 
Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil vultus comedat cerebella viventium. 
Nescio brains an Undead zombies. Sicut malus putrid voodoo horror. Nigh tofth eliv ingdead.
</p>

我使用$anchorScroll服务。为了抵消随散列改变而来的页面刷新,我取消了locationChangeStart事件。这对我来说很有效,因为我有一个连接到ng-switch的帮助页面,而刷新基本上会破坏应用程序。

$anchorScroll可以解决这个问题,但在Angular的最新版本中,有更好的方法来使用它。

现在,$anchorScroll接受散列作为可选参数,因此您不必更改$location。完全是散列。(文档)

这是最好的解决方案,因为它完全不影响路线。我不能得到任何其他解决方案的工作,因为我使用ngRoute和路由将重新加载,只要我设置$location.hash(id),之前$anchorScroll可以做它的魔法。

下面是如何使用它…首先,在指令或控制器中:

$scope.scrollTo = function (id) {
  $anchorScroll(id);  
}

然后在视图中:

<a href="" ng-click="scrollTo(id)">Text</a>

同样,如果你需要考虑一个固定的导航栏(或其他UI),你可以像这样设置$anchorScroll的偏移量(在主模块的run函数中):

.run(function ($anchorScroll) {
   //this will make anchorScroll scroll to the div minus 50px
   $anchorScroll.yOffset = 50;
});

你可以尝试使用anchorScroll。

例子

所以控制器会是:

app.controller('MainCtrl', function($scope, $location, $anchorScroll, $routeParams) {
  $scope.scrollTo = function(id) {
     $location.hash(id);
     $anchorScroll();
  }
});

和视图:

<a href="" ng-click="scrollTo('foo')">Scroll to #foo</a>

...锚的id也没有秘密:

<div id="foo">
  This is #foo
</div>

我可以这样做:

<li>
<a href="#/#about">About</a>
</li>