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

Ras*_*mus 318 javascript anchor hashtag 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>
Run Code Online (Sandbox Code Playgroud)

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

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

但是然后AngularJS又一次打击我,只是滚动到页面的顶部.

所以,这里的任何人都做过类似的事情并且知道一个很好的解决方案吗?

编辑:切换到html5Mode应该解决我的问题,但我们有点必须支持IE8 +所以我担心它不是一个公认的解决方案:/

Ben*_*esh 373

你在找$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>
Run Code Online (Sandbox Code Playgroud)

这是一个展示的掠夺者

编辑:使用此与路由

像往常一样设置角度路由,然后添加以下代码.

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();  
  });
});
Run Code Online (Sandbox Code Playgroud)

你的链接看起来像这样:

<a href="#/test?scrollTo=foo">Test/Foo</a>
Run Code Online (Sandbox Code Playgroud)

这是一个使用路由和$ 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();  
  });
});
Run Code Online (Sandbox Code Playgroud)

你的链接看起来像这样:

<a href="#/test#foo">Test/Foo</a>
Run Code Online (Sandbox Code Playgroud)

  • 此解决方案使我的整个应用程序重新呈现. (24认同)
  • 添加路由时可能会出现问题:如果添加ngView,每次更改url的哈希都会触发路由重新加载...在你的示例中没有路由,url不反映当前项...但是感谢指向$ anchorScroll (5认同)
  • @blesh:我建议你在滚动到所需的部分后删除哈希,这样URL就不会被真正不应该存在的东西所污染.使用:`$ location.search('scrollTo',null)` (4认同)
  • @dsldsl && @OliverJosephAsh:$ location.hash()不会重新加载页面.如果是的话,还有其他事情要发生.[这是同样的插件,随着页面加载时写出来,你会看到它没有改变](http://plnkr.co/edit/MuOY3mE1SfWAHkD1ijpk?p=preview)如果你想要滚动对于当前页面上的锚标记而不重新加载路径,您只需要定期链接`<a href="#foo"> foo </a>`.我的代码示例是在routechange上显示滚动到id. (2认同)

小智 168

在我的情况下,我注意到如果我修改了路由逻辑,它就会被激活$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);
};
Run Code Online (Sandbox Code Playgroud)

  • 你的"拯救旧哈希"技巧一直是绝对的救星.它可以防止页面重新加载,同时保持路由清洁.真棒的想法! (8认同)
  • 非常感谢,即使使用@ blesh的.run(...)解决方案,路由逻辑绝对拒绝表现,并对此进行排序. (5认同)
  • 我用`$ location.hash(my_id); $ anchorScroll; $的location.hash(空)`.它阻止了重载,我不必管理`old`变量. (3认同)
  • 好一个.但在实施解决方案后,url不会更新目标ID的值. (2认同)

Mau*_*rez 53

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>
Run Code Online (Sandbox Code Playgroud)

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

<h3 id="faq-1">Question 1</h3>
<h3 id="faq-2">Question 2</h3>
<h3 id="faq-3">Question 3</h3>
Run Code Online (Sandbox Code Playgroud)

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

  • 谢谢你的解决方案.但是target ="_ self"就足够了.无需加倍# (6认同)
  • target ="_ self"绝对是最好的答案(不需要加倍#,正如Christophe P所指出的那样).无论Html5Mode是打开还是关闭,这都有效. (5认同)
  • 这是正确的解决方案.无需涉及角度$ anchorScroll服务.请参阅标记文档:[https://developer.mozilla.org/en/docs/Web/HTML/Element/a](https://developer.mozilla.org/en/docs/Web/HTML/Element/一个) (4认同)
  • 简单而完整.为我工作而不需要添加另一个角度依赖. (3认同)
  • 这对我不起作用,但这里的解决方案确实如此:http://stackoverflow.com/a/19367249/633107 (2认同)

lin*_*nge 41

<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>
Run Code Online (Sandbox Code Playgroud)

  • 这看起来相对简单但不起作用:-( (9认同)
  • 我添加了target ="_ self",它对于页面内的所有类型的导航都起了吸引力(读取滑块,转到不同的部分等).感谢您分享这个伟大而简单的技巧. (4认同)

小智 19

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

href="#/route#anchorID
Run Code Online (Sandbox Code Playgroud)

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

  • @RobinWassén-Andersson通过在路由配置中为该路由指定`reloadOnSearch:false`,angular不会触发路由更改,只会滚动到id.结合`a`标签中指定的完整路线,我想说这是最简单,最直接的解决方案. (9认同)

Kha*_*nna 13

这是我的解决方案使用一个似乎更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();
    });

  };
});
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

我使用了$ anchorScroll服务.为了抵消随着哈希变化而进行的页面刷新,我继续前进并取消了locationChangeStart事件.这对我有用,因为我有一个连接到ng-switch的帮助页面,刷新将彻底破坏应用程序.

  • 您需要从locationChangeStart事件取消取消:var off = scope.$ on('$ locationChangeStart',function(ev){off(); ev.preventDefault();}); (2认同)

Reb*_*cca 13

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

现在,$anchorScroll接受哈希作为可选参数,因此您根本不需要更改$location.hash.(文件)

这是最好的解决方案,因为它根本不会影响路线.我无法使用任何其他解决方案,因为我正在使用ngRoute,并且路由会在我设置$location.hash(id)之后立即重新加载,然后$anchorScroll才能发挥其魔力.

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

$scope.scrollTo = function (id) {
  $anchorScroll(id);  
}
Run Code Online (Sandbox Code Playgroud)

然后在视图中:

<a href="" ng-click="scrollTo(id)">Text</a>
Run Code Online (Sandbox Code Playgroud)

此外,如果您需要考虑固定的导航栏(或其他UI),您可以像这样设置$ anchorScroll的偏移量(在主模块的运行功能中):

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

  • 通过将Id直接传递给$ anchorScroll,我的路由从/ contact#contact变为just/contact.这应该是接受的答案imho. (2认同)

Max*_*ach 5

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

完整示例:

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

  • 你确定吗.为什么这不起作用?如果哈希前缀是!,那么哈希路由应该是#!page.因此,AngularJS应该检测它何时只是#hash,它应该自动锚定滚动并且适用于HTML5模式URL和散列模式URL. (2认同)

小智 5

我在我的应用程序的路由逻辑中解决了这个问题.

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;
      }
    });
}
Run Code Online (Sandbox Code Playgroud)


Ben*_*min 5

这是一篇很老的帖子,但我花了很长时间研究各种解决方案,所以我想分享一个更简单的解决方案.只需添加target="_self"<a>标签固定对我来说.该链接有效,并将我带到页面上的正确位置.

但是,Angular仍会在URL中使用#注入一些奇怪的内容,因此在使用此方法后使用后退按钮进行导航可能会遇到麻烦.