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

IT技术 javascript angularjs anchor hashtag
2021-02-08 16:37:00

你们中有人知道如何在AngularJS 中很好地处理锚点哈希链接吗?

我有一个简单的常见问题解答页面的以下标记

<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+,所以我担心这不是一个可以接受的解决方案:/

6个回答

您正在寻找$anchorScroll().

这是(蹩脚的)文档。

这是来源。

基本上,您只需注入它并在您的控制器中调用它,它就会将您滚动到具有 id 的任何元素 $location.hash()

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>

这是一个plunker来演示

编辑:将其与路由一起使用

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

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>

这是一个展示使用路由和 $anchorScroll 滚动的Plunker

甚至更简单:

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>
@blesh:我建议您在滚动到所需部分后也删除哈希,这样 URL 就不会被真正不应该存在的东西污染。用这个: $location.search('scrollTo', null)
2021-03-11 16:37:00
添加路由时可能会出现问题:如果添加 ngView,每次更改 url 的哈希值都会触发路由重新加载...在您的示例中,没有路由并且 url 不反映当前项目...但感谢您指向 $anchorScroll
2021-03-12 16:37:00
此解决方案导致我的整个应用程序重新呈现。
2021-03-21 16:37:00
@blesh,调用 location.hash(X) 更改页面,因为路由控制视图。
2021-03-23 16:37:00
@dsldsl && @OliverJosephAsh:$location.hash() 不会重新加载页面。如果是这样,还有其他事情正在发生。这是与页面加载时写出的时间相同的 plunk,您会看到它不会改变 如果您想滚动到当前页面上的锚标记而不重新加载路由,您只需执行定期链接<a href="#foo">foo</a>我的代码示例是在 routechange 上显示滚动到 id。
2021-04-03 16:37:00

就我而言,我注意到如果我修改了$location.hash(). 以下技巧奏效了..

$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);
};
您的“保存旧哈希”技巧绝对是救命稻草。它可以防止页面重新加载,同时保持路线清洁。真棒的想法!
2021-03-16 16:37:00
非常感谢,即使使用@blesh 的 .run(...) 解决方案,路由逻辑也绝对拒绝采取行动,这对它进行了排序。
2021-03-27 16:37:00
我和 Mohamed 有同样的经历......它确实停止了重新加载,但它显示了无哈希路由(并且 $anchorScroll 没有效果)。1.2.6 嗯嗯。
2021-04-06 16:37:00
我用$location.hash(my_id); $anchorScroll; $location.hash(null). 它可以防止重新加载,而且我不必管理old变量。
2021-04-08 16:37:00
好东西。但是在实施您的解决方案后,该 url 不会更新目标 id 的值。
2021-04-09 16:37:00

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>

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

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

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

这是正确的解决方案。无需涉及角度 $anchorScroll 服务。查看标签文档:https : //developer.mozilla.org/en/docs/Web/HTML/Element/a
2021-03-14 16:37:00
target="_self" 绝对是最好的答案(无需重复 #,正如 Christophe P 所指出的那样)。无论 Html5Mode 是打开还是关闭,这都有效。
2021-03-16 16:37:00
这对我不起作用,但这里的解决方案确实如此:stackoverflow.com/a/19367249/633107
2021-03-17 16:37:00
感谢您提供此解决方案。但是 target="_self" 就足够了。无需加倍#
2021-04-04 16:37:00
简单而完整。为我工作而无需添加另一个角度依赖项。
2021-04-04 16:37:00
<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>
这看起来相对简单,但它不起作用:-(
2021-03-23 16:37:00
我添加了 target="_self" 并且它对页面内的所有类型的导航都很有用(阅读滑块,转到不同的部分等等)。感谢您分享这个伟大而简单的技巧。
2021-03-28 16:37:00
根据我的经验,href="##" 仅在注入 $anchorScroll 时有效。
2021-03-29 16:37:00
我认为它与AngularJS中的解决方案(/products##books)相同
2021-03-31 16:37:00
惊人的!到目前为止最简单的解决方案,但知道如何链接到单独页面上的锚点吗?(即 /products#books )
2021-04-08 16:37:00

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

href="#/route#anchorID

route当前的角度路线在哪里anchorID匹配<a id="anchorID">页面上的某个地方

这会触发正常的 AngularJS 路由更改,因此不鼓励这样做。就我而言,这是非常直观的,因为常见问题解答/帮助页面中的 YouTube 视频重新加载。
2021-03-22 16:37:00
谢谢你。这对我有帮助。我没有在我的应用程序中使用任何自定义路由,所以做一个 href="#/#anchor-name" 效果很好!
2021-04-01 16:37:00
@RobinWassén-Andersson 通过reloadOnSearch: false在路由配置中指定该路由,angular 不会触发路由更改,只会滚动到 id。结合a标签中指定的完整路线,我会说这是最简单和最直接的解决方案。
2021-04-10 16:37:00