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

2020/10/03 22:41 · javascript ·  · 0评论

你们中有谁知道如何在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 +,所以我担心这不是一个可以接受的解决方案:/

您正在寻找$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>

这是一个示范的朋克

编辑:与路由一起使用

像往常一样设置角度布线,然后只需添加以下代码。

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>

就我而言,我注意到如果修改,路由逻辑就会开始$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);
};

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>

idhtml元素中使用属性,如下所示:

<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">页面上的某个位置匹配

$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;
});

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

在这边

的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-switch的帮助页面,刷新本质上会破坏该应用程序。

尝试为角度路线设置哈希前缀 $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的新属性,但是我已经能够angular-route使用ngView autoscroll属性和'double-hashhes'使其锚定哈希链接

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

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

如果您不喜欢使用ng-click此处,则可以选择其他解决方案。它使用filter来根据当前状态生成正确的网址。我的示例使用ui.router

好处是用户将看到链接在悬停时的位置。

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

过滤器:

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

我的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>

我试图将我的Angular应用滚动到加载的锚opon上,并遇到$ routeProvider的URL重写规则。

经过长时间的试验,我决定这样做:

  1. 从Angular应用程序模块的.run()部分注册document.onload事件处理程序。
  2. 在处理程序中,通过执行一些字符串操作,找出原来的具有anchor标签的内容。
  3. 用剥离的锚标记覆盖location.hash(这会导致$ routeProvider立即使用“#/”规则再次覆盖它。但这很好,因为Angular现在与URL 4中的内容保持同步)调用$ 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();
			}
		}	 
 });

我不是100%肯定这是否一直有效,但是在我的应用程序中,这给了我预期的行为。

假设您在ABOUT页面上,并且路线如下:

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>

结论

在锚点之前添加页面名称对我有用。让我知道您的想法。

缺点

这将重新渲染页面,然后滚动到锚点。

更新

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

<a href="#tab1" onclick="return false;">First Part</a>

轻松获取滚动功能。它还支持动画/平滑滚动作为附加功能。Angular Scroll库的详细信息

Github - https://github.com/oblador/angular-scroll

鲍尔bower install --save angular-scroll

npmnpm install --save angular-scroll

精简版-仅9kb

平滑滚动(动画滚动) -是

滚动间谍-是的

文档-出色

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

希望这可以帮助。

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

[reloadOnSearch = true]-{boolean =}-仅更改$ location.search()或$ location.hash()时重新加载路由。

将此设置为false可以解决上述所有问题。

基于@Stoyan,我提出了以下解决方案:

app.run(function($location, $anchorScroll){
    var uri = window.location.href;

    if(uri.length >= 4){

        var parts = uri.split('#!#');
        if(parts.length > 1){
            var anchor = parts[parts.length -1];
            $location.hash(anchor);
            $anchorScroll();
        }
    }
});

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

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

将此代码放在您的控制器上。

我认为@slugslog拥有它,但是我会改变一件事。我将使用replace代替,因此您不必重新设置它。

$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">

我正在使用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进行任何更改。

本文地址:http://javascript.askforanswer.com/ruhezaiangularjszhongchulimaodianhaxilianjie.html
文章标签: ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!