324

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 +をサポートする必要があるため、受け入れられた解決策ではないのではないかと心配しています:/

4

28 に答える 28

379

を探してい$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>

ここにデモンストレーションするプランカーがあります

編集:これをルーティングで使用するには

いつものようにAngularルーティングをセットアップしてから、次のコードを追加してください。

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 を使用したスクロールを示すプランカーです。

そしてさらに簡単です:

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>
于 2013-02-05T21:14:00.133 に答える
171

私の場合、$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);
};
于 2013-04-10T20:13:01.617 に答える
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>

そして、次のようにhtml要素 idで属性を使用します。

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

コメントで指摘/言及されているように、## を使用する必要はありません ;-)

于 2015-07-19T20:33:18.487 に答える
20

ルートが常にわかっている場合は、次のようにアンカーを追加するだけです。

href="#/route#anchorID

whererouteは現在の角度ルートで、ページのどこかにanchorID一致します<a id="anchorID">

于 2013-10-14T18:57:10.717 に答える
14

$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 関数内)。

.run(function ($anchorScroll) {
   //this will make anchorScroll scroll to the div minus 50px
   $anchorScroll.yOffset = 50;
});
于 2016-01-27T04:27:33.167 に答える
13

これは、DOM を扱っているため、より Angular-y に見えるディレクティブを使用した私のソリューションでした。

ここのPlkr

ギットハブ

コード

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 に接続されたヘルプ ページがあり、更新によって本質的にアプリが壊れてしまうため、これはうまくいきました。

于 2013-07-29T16:05:17.993 に答える
5

angularルートのハッシュプレフィックスを設定してみてください$locationProvider.hashPrefix('!')

完全な例:

angular.module('app', [])
  .config(['$routeProvider', '$locationProvider', 
    function($routeProvider, $locationProvider){
      $routeProvider.when( ... );
      $locationProvider.hashPrefix('!');
    }
  ])
于 2013-02-05T18:23:07.700 に答える
3

私はこれを次のように行うことができます:

<li>
<a href="#/#about">About</a>
</li>
于 2015-12-03T19:07:35.623 に答える
2

使用したくない場合は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;
    };
}])
于 2016-04-06T13:11:03.160 に答える
2
<a href="/#/#faq-1">Question 1</a>
<a href="/#/#faq-2">Question 2</a>
<a href="/#/#faq-3">Question 3</a>
于 2015-05-19T20:32:43.520 に答える
2

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>
于 2016-11-17T11:13:54.300 に答える
2

指定された要素にスクロールするカスタムディレクティブを作成することによる、一種の汚い回避策があります(ハードコードされた「faq」を使用)

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

于 2013-02-05T17:04:56.193 に答える
1

Angular アプリをロード時にアンカーまでスクロールさせようとしていたところ、$routeProvider の URL 書き換えルールに遭遇しました。

長い実験の後、私はこれに落ち着きました:

  1. Angular アプリ モジュールの .run() セクションから document.onload イベント ハンドラーを登録します。
  2. ハンドラーで、いくつかの文字列操作を実行して、元のアンカー タグが本来あるべきものを見つけます。
  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();
			}
		}	 
 });

于 2014-10-22T02:59:39.897 に答える
1

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>
于 2013-10-24T01:55:34.440 に答える
0

私の考えでは、@slugslog にはそれがありましたが、1 つ変更します。代わりに replace を使用するので、元に戻す必要はありません。

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

「置換メソッド」をドキュメントで検索

于 2015-02-04T19:51:00.753 に答える
0

これを試すと、アンカーの問題が解決します。

app.run(function($location, $anchorScroll){
    document.querySelectorAll('a[href^="#"]').forEach(anchor => {
        anchor.addEventListener('click', function (e) {
            e.preventDefault();

            document.querySelector(this.getAttribute('href')).scrollIntoView({
                behavior: 'smooth'
            });
        });
    });
});
于 2021-07-08T14:42:02.867 に答える