如何在AngularJS中处理锚点哈希链接

你们有没有人知道如何很好地处理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.chapter,然后使用jQuery向下滚动。 但是,然后AngularJS再次让我感到害怕,只是滚动到页面的顶部。

那么,这里的任何人在过去做过类似的事情,并且知道一个很好的解决办法呢?

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

您正在寻找$anchorScroll()

这是(糟糕的)文档。

这里的来源。

基本上你只是注入它,并在你的控制器中调用它,它会滚动你的任何元素与$location.hash()找到的ID

 app.controller('TestCtrl', function($scope, $location, $anchorScroll) { $scope.scrollTo = function(id) { $location.hash(id); $anchorScroll(); } }); <a ng-click="scrollTo('foo')">Foo</a> <div id="foo">Here you are</div> 

这是一个暴徒来演示

编辑:使用此路由

像往常一样设置角度路由,然后添加下面的代码。

 app.run(function($rootScope, $location, $anchorScroll, $routeParams) { //when the route is changed scroll to the proper element. $rootScope.$on('$routeChangeSuccess', function(newRoute, oldRoute) { $location.hash($routeParams.scrollTo); $anchorScroll(); }); }); 

你的链接将如下所示:

 <a href="#/test?scrollTo=foo">Test/Foo</a> 

这里是一个Plunker演示滚动路由和$ anchorScroll

甚至更简单:

 app.run(function($rootScope, $location, $anchorScroll) { //when the route is changed scroll to the proper element. $rootScope.$on('$routeChangeSuccess', function(newRoute, oldRoute) { if($location.hash()) $anchorScroll(); }); }); 

你的链接将如下所示:

 <a href="#/test#foo">Test/Foo</a> 

在我的情况下,我注意到,如果我修改了位置散列,路由逻辑正在踢。 下面的技巧工作..

 $scope.scrollTo = function(id) { var old = $location.hash(); $location.hash(id); $anchorScroll(); //reset to old to keep any additional routing logic from kicking in $location.hash(old); }; 

没有必要改变任何路由或其他任何东西只需要在创建链接时使用target="_self"

例:

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

在你的html元素中使用id属性,如下所示:

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

没有必要使用##在评论中指出/提到;-)

 <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="faq-3">Question 3</h3> 

如果你总是知道路线,你可以简单地追加这样的锚点:

 href="#/route#anchorID 

其中route是当前角路由, anchorID与页面某处的<a id="anchorID">匹配

这是我的解决方案,使用一个更像Angular-y的指令,因为我们正在处理DOM:

Plnkr在这里

github上

 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开关和刷新将实际上打破了应用程序。

$anchorScroll适用于此,但在更新版本的Angular中有更好的方法来使用它。

现在, $anchorScroll接受散列作为一个可选的参数,所以你不必改变$location.hash 。 ( 文件 )

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

这里是如何使用它…首先,在指令或控制器:

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

然后在视图中:

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

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

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

尝试为角度路由设置哈希前缀$locationProvider.hashPrefix('!')

完整的例子:

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

我在路线逻辑中为我的应用程序解决了这个问题。

 function config($routeProvider) { $routeProvider .when('/', { templateUrl: '/partials/search.html', controller: 'ctrlMain' }) .otherwise({ // Angular interferes with anchor links, so this function preserves the // requested hash while still invoking the default route. redirectTo: function() { // Strips the leading '#/' from the current hash value. var hash = '#' + window.location.hash.replace(/^#\//g, ''); window.location.hash = hash; return '/' + hash; } }); } 

这是一个老帖子,但我花了很长时间研究各种解决方案,所以我想分享一个更简单的。 只需将< target="_self"<a>标记中即可。 链接工作,并带我到页面上的适当位置。

然而,Angular仍然会在URL中注入一些怪异的东西,所以在使用这个方法之后,你可能会遇到使用后退按钮导航的麻烦。

这可能是ngView的一个新属性,但是我已经能够通过使用ngView autoscroll属性和“double-hashes”来获得锚链接哈希链接来使用angular-route

ngView(请参阅自动滚动)

(下面的代码被用于角度绑带)

 <!-- 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> 

我可以这样做:

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

这是一种肮脏的解决方法,通过创建自定义指令,将滚动到指定的元素(硬编码“常见问题”)

 app.directive('h3', function($routeParams) { return { restrict: 'E', link: function(scope, element, attrs){ if ('faq'+$routeParams.v == attrs.id) { setTimeout(function() { window.scrollTo(0, element[0].offsetTop); },1); } } }; }); 

http://plnkr.co/edit/Po37JFeP5IsNoz5ZycFs?p=preview

我用ng-route的解决方案就是这个简单的指令:

  app.directive('scrollto', function ($anchorScroll,$location) { return { link: function (scope, element, attrs) { element.click(function (e) { e.preventDefault(); $location.hash(attrs["scrollto"]); $anchorScroll(); }); } }; }) 

该html看起来像:

 <a href="" scrollTo="yourid">link</a> 

你可以尝试使用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> 

我不是100%肯定,如果这一直工作,但在我的应用程序,这给了我预期的行为。

让我们说你在关于页面,你有以下路线:

 yourApp.config(['$routeProvider', function($routeProvider) { $routeProvider. when('/about', { templateUrl: 'about.html', controller: 'AboutCtrl' }). otherwise({ redirectTo: '/' }); } ]); 

现在,在你的HTML

 <ul> <li><a href="#/about#tab1">First Part</a></li> <li><a href="#/about#tab2">Second Part</a></li> <li><a href="#/about#tab3">Third Part</a></li> </ul> <div id="tab1">1</div> <div id="tab2">2</div> <div id="tab3">3</div> 

结论是

在锚之前包括页面名称为我做了窍门。 让我知道你的想法。

下行

这将重新呈现页面,然后滚动到锚点。

UPDATE

更好的方法是添加以下内容:

 <a href="#tab1" onclick="return false;">First Part</a> 
 <a href="/#/#faq-1">Question 1</a> <a href="/#/#faq-2">Question 2</a> <a href="/#/#faq-3">Question 3</a> 

如果你不喜欢使用ng-click这是另一种解决方案。 它使用filter根据当前状态生成正确的URL。 我的例子使用ui.router

好处是,用户将看到链接进行悬停的位置。

 <a href="{{ 'my-element-id' | anchor }}">My element</a> 

过滤器:

 .filter('anchor', ['$state', function($state) { return function(id) { return '/#' + $state.current.url + '#' + id; }; }]) 

轻松获得滚动功能。 它还支持动画/平滑滚动作为一个额外的功能。 Angular Scroll Library的详细信息:

Githubhttps://github.com/oblador/angular-scroll

鲍尔bower install --save angular-scroll

npmnpm install --save angular-scroll

最小版本 – 只有9kb

平滑滚动(动画滚动) – 是的

滚动间谍 – 是的

文档 – 优秀

演示http://oblador.github.io/angular-scroll/

希望这可以帮助。

我试图让我的Angular应用程序滚动到一个锚点opon加载,并跑到$ routeProvider的URL重写规则。

经过长时间的实验,我决定了这个:

  1. 从Angular应用程序模块的.run()部分注册document.onload事件处理程序。
  2. 在处理程序中找出原始的锚标签是通过做一些字符串操作应该是什么。
  3. 重写location.hash与剥离的锚点标签(这导致$ routeProvider立即用它的“#/”规则覆盖它,但这很好,因为Angular现在与URL中的内容同步) $ anchorScroll()。
 angular.module("bla",[]).}]) .run(function($location, $anchorScroll){ $(document).ready(function() { if(location.hash && location.hash.length>=1) { var path = location.hash; var potentialAnchor = path.substring(path.lastIndexOf("/")+1); if ($("#" + potentialAnchor).length > 0) { // make sure this hashtag exists in the doc. location.hash = potentialAnchor; $anchorScroll(); } } }); 

在更改路线时,它将滚动到页面的顶部。

  $scope.$on('$routeChangeSuccess', function () { window.scrollTo(0, 0); }); 

把这个代码放在你的控制器上。

在我的脑海里,有了它,但我会改变一件事。 我会使用替换,所以你不必把它设置回来。

 $scope.scrollTo = function(id) { var old = $location.hash(); $location.hash(id).replace(); $anchorScroll(); }; 

文档搜索“替换方法”

上面的解决方案都不适用于我,但我只是尝试了这一点,它的工作,

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

所以我意识到我需要通知页面开始索引页面,然后使用传统的锚点。

有时在angularjs应用程序的哈希导航不工作和引导jquery JavaScript库广泛使用这种类型的导航,使其工作添加target="_self"锚定标记。 例如<a data-toggle="tab" href="#id_of_div_to_navigate" target="_self">

https://code.angularjs.org/1.4.10/docs/api/ngRoute/provider/ $ routeProvider

[reloadOnSearch = true] – {boolean =} – 只有$ location.search()或者$ location.hash()发生变化时重载路由。

把这个设置为false,对我来说没有任何上述的窍门。

我使用AngularJS 1.3.15,看起来我不需要做任何特别的事情。

https://code.angularjs.org/1.3.15/docs/api/ng/provider/ $ anchorScrollProvider

所以,下面的代码在我的html中工作:

 <ul> <li ng-repeat="page in pages"><a ng-href="#{{'id-'+id}}">{{id}}</a> </li> </ul> <div ng-attr-id="{{'id-'+id}}" </div> 

我不必对控制器或JavaScript进行任何更改。

Interesting Posts