web-dev-qa-db-ja.com

ルートを変更しても新しいページで一番上にスクロールしない

私は、経路が変わるときに、少なくとも私にとっては望ましくない動作を見つけました。チュートリアルのステップ11 http://angular.github.io/angular-phonecat/step-11/app /#/phones 電話のリストを見なさい。一番下までスクロールして最新のものをクリックすると、スクロールが一番上には表示されず、中央に表示されます。

私は自分のアプリの1つでもこれを見つけましたが、どうやってこれを一番上までスクロールさせることができるのか疑問に思いました。私はそれを手動で行うことができますが、これを行うための他のエレガントな方法があるべきだと私は思いますが、私は知りません。

それで、ルートが変わったときに上にスクロールするための優雅な方法はありますか?

270
Matias Gonzalez

問題は、ngViewが新しいビューをロードしたときにスクロール位置を保持することです。 $anchorScrollに "ビューが更新された後にビューポートをスクロールする"ように指示することができます( ドキュメント は少しあいまいですが、ここでスクロールすると新しいビューの最上部までスクロールします。

解決策はあなたのngView要素にautoscroll="true"を追加することです。

<div class="ng-view" autoscroll="true"></div>
575
Konrad Kiss

このコードを実行するだけで

$rootScope.$on("$routeChangeSuccess", function (event, currentRoute, previousRoute) {

    window.scrollTo(0, 0);

});
44
xmaster

このコードは私にとってはうまくいきました。それがあなたにとってもうまくいくことを私は願っています。

 angular.module('myAngularApp')
.run(function($rootScope, Auth, $state, $anchorScroll){
    $rootScope.$on("$locationChangeSuccess", function(){
        $anchorScroll();
    });

Angularjsモジュールの呼び出し順序は次のとおりです。

  1. app.config()
  2. app.run()
  3. directive's compile functions (if they are found in the dom)
  4. app.controller()
  5. directive's link functions (again, if found)

RUN BLOCKは、インジェクタが作成された後に実行され、アプリケーションのキックスタートに使用されます。つまり、新しいルートビューにリダイレクトされると、実行ブロックは

$ anchorScroll()

これで、スクロールが新しいルーテッドビューで上から始まります。

36
Rizwan Jamal

ui-view autoscroll=true$stateChangeStart$locationChangeStart$uiViewScrollProvider.useAnchorScroll()$provide('$uiViewScroll', ...)、およびその他多くの組み合わせを試して1〜2時間経った後、期待どおりに新しいページの上にスクロールすることができませんでした。

これは最終的に私のために働いたものでした。 pushStateとreplaceStateをキャプチャし、新しいページに移動したときにのみスクロール位置を更新します(戻る/進むボタンはそれぞれのスクロール位置を保持します)。

.run(function($anchorScroll, $window) {
  // hack to scroll to top when navigating to new URLS but not back/forward
  var wrap = function(method) {
    var orig = $window.window.history[method];
    $window.window.history[method] = function() {
      var retval = orig.apply(this, Array.prototype.slice.call(arguments));
      $anchorScroll();
      return retval;
    };
  };
  wrap('pushState');
  wrap('replaceState');
})
31
wkonkel

これは私の(一見)堅牢で完全かつ(かなり)簡潔な解決策です。それは縮小互換スタイル(そしてあなたのモジュールへのangular.module(NAME)アクセス)を使用します。

angular.module('yourModuleName').run(["$rootScope", "$anchorScroll" , function ($rootScope, $anchorScroll) {
    $rootScope.$on("$locationChangeSuccess", function() {
                $anchorScroll();
    });
}]);

PS私は、autoscrollがtrueかfalseに設定されていても効果がないことを発見しました。

18
James

Angularjs UIルーターを使用して、私がやっているのはこれです:

    .state('myState', {
        url: '/myState',
        templateUrl: 'app/views/myState.html',
        onEnter: scrollContent
    })

と:

var scrollContent = function() {
    // Your favorite scroll method here
};

どのページでも失敗することはなく、グローバルではありません。

15
Léon Pelletier

Angular UIルーター ( - === - )プラグイン...

このSO質問で尋ねられて答えたように、route-uiルーターはあなたがルートを変更するとページの一番下にジャンプします。
ページが一番下に表示される理由がわかりませんか。 Angular UIルーターの自動スクロールの問題

しかし、答えが述べているように、あなたはあなたのautoscroll="false"ui-viewを言うことによってこの振る舞いを止めることができます。

例えば:

<div ui-view="pagecontent" autoscroll="false"></div>
<div ui-view="sidebar" autoscroll="false"></div> 

http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.directive:ui-view

13
mg1075

あなたはこのJavaScriptを使用することができます

$anchorScroll()
7
CodeIsLife

あなたは(実行時に)あなたが使用することができますUIルータを使用する場合

$rootScope.$on("$stateChangeSuccess", function (event, currentState, previousState) {
    $window.scrollTo(0, 0);
});
7
Colzak

私はこの解決策を見つけました。新しいビューに移動すると、関数が実行されます。

var app = angular.module('hoofdModule', ['ngRoute']);

    app.controller('indexController', function ($scope, $window) {
        $scope.$on('$viewContentLoaded', function () {
            $window.scrollTo(0, 0);
        });
    });
4
Vince Verhoeven

パーティーには少し遅れましたが、可能な限りの方法を試してみましたが、何も正しく機能しませんでした。これが私のエレガントな解決策です。

私はすべてのページを管理するコントローラをui-routerで使用しています。認証も検証もされていないユーザーを適切な場所にリダイレクトできます。ほとんどの人はミドルウェアを自分のアプリの設定に入れていますが、私はいくつかのhttpリクエストを必要としていました。そのため、グローバルコントローラが私にとってはより良く機能します。

私のindex.htmlはこんな感じです:

<main ng-controller="InitCtrl">
    <nav id="top-nav"></nav>
    <div ui-view></div>
</main>

私のinitCtrl.jsはこんな感じです:

angular.module('MyApp').controller('InitCtrl', function($rootScope, $timeout, $anchorScroll) {
    $rootScope.$on('$locationChangeStart', function(event, next, current){
        // middleware
    });
    $rootScope.$on("$locationChangeSuccess", function(){
        $timeout(function() {
            $anchorScroll('top-nav');
       });
    });
});

私はすべての可能な選択肢を試してみました、この方法は最もうまくいきます。

3
BuffMcBigHuge

AutoScrollをtrueに設定しても私にはうまくいきませんでしたので、別の解決策を選びました。私はルートが変わるたびにフックするサービスを作りました、そしてそれは一番上にスクロールするために組み込みの$ anchorScrollサービスを使います。私のために働きます:-)。

サービス:

 (function() {
    "use strict";

    angular
        .module("mymodule")
        .factory("pageSwitch", pageSwitch);

    pageSwitch.$inject = ["$rootScope", "$anchorScroll"];

    function pageSwitch($rootScope, $anchorScroll) {
        var registerListener = _.once(function() {
            $rootScope.$on("$locationChangeSuccess", scrollToTop);
        });

        return {
            registerListener: registerListener
        };

        function scrollToTop() {
            $anchorScroll();
        }
    }
}());

登録:

angular.module("mymodule").run(["pageSwitch", function (pageSwitch) {
    pageSwitch.registerListener();
}]);
3
asp_net

提供された答えのどれも私の問題を解決しませんでした。ビュー間でアニメーションを使用していますが、スクロールは常にアニメーションの後に行われます。私が見つけた解決策は、アニメーションの前に一番上までスクロールすることが次のディレクティブであることです。

yourModule.directive('scrollToTopBeforeAnimation', ['$animate', function ($animate) {
    return {
        restrict: 'A',
        link: function ($scope, element) {
            $animate.on('enter', element, function (element, phase) {

                if (phase === 'start') {

                    window.scrollTo(0, 0);
                }

            })
        }
    };
}]);

私の意見では、次のように挿入しました。

<div scroll-to-top-before-animation>
    <div ng-view class="view-animation"></div>
</div>
2
aBertrand

上記のすべての答えは予想されるブラウザの動作を壊します。ほとんどの人が望むのは、それが「新しい」ページの場合は上にスクロールするが、[戻る](または[進む])ボタンを使用して移動した場合は前の位置に戻るものです。

あなたがHTML5モードを想定しているなら、これは簡単であることがわかります(けれども、これをもっと優雅にする方法を考え出すことができると確信している人もいますが!)

// Called when browser back/forward used
window.onpopstate = function() { 
    $timeout.cancel(doc_scrolling); 
};

// Called after ui-router changes state (but sadly before onpopstate)
$scope.$on('$stateChangeSuccess', function() {
    doc_scrolling = $timeout( scroll_top, 50 );

// Moves entire browser window to top
scroll_top = function() {
    document.body.scrollTop = document.documentElement.scrollTop = 0;
}

それが動作する方法は、ルーターはそれが一番上にスクロールすることを想定していますが、ブラウザが終了する機会を与えるために少し遅れることです。ブラウザが変更が「戻る/進む」ナビゲーションによるものであることを通知した場合、タイムアウトはキャンセルされ、スクロールは発生しません。

ウィンドウの上部全体に移動したいので、スクロールに生のdocumentコマンドを使用しました。 ui-viewをスクロールさせたいだけの場合は、上記の手法を使用してautoscroll="my_var"を制御する場所にmy_varを設定します。しかし、私があなたが "new"としてページに行くのであれば、ほとんどの人はページ全体をスクロールしたいと思うでしょう。

上記ではui-routerを使用していますが、代わりに$routeChangeSuccess for$stateChangeSuccessを交換することでng-routeを使用できます。

2
Dev93

単純な解決策として、有効にされたメインルートモジュールにscrollPositionRestorationを追加します。
このような:

const routes: Routes = [

 {
   path: 'registration',
   loadChildren: () => RegistrationModule
},
];

 @NgModule({
  imports: [
   RouterModule.forRoot(routes,{scrollPositionRestoration:'enabled'})
  ],
 exports: [
 RouterModule
 ]
 })
  export class AppRoutingModule { }
2
Farida Anjum

試してください http://ionicframework.com/docs/api/service/ $ionicScrollDelegate /

リストの一番上までスクロールします。scrollTop()

0
ToughPal

これは自動スクロールを含む私のために働きました

<div class="ngView" autoscroll="true" >

0
Teja

私はようやく必要なものを手に入れました。

一番上までスクロールする必要がありましたが、いくつかの遷移がにならないようにしました

これはルートごとに制御できます。
@wkonkelによる上記の解決策を組み合わせて、いくつかのルート宣言に単純なnoScroll: trueパラメータを追加しています。それから私は移行中にそれを捉えています。

全体として:これは新しいトランジションではページの一番上に浮かぶが、Forward/Backのトランジションでは一番上に浮かぶことはなく、必要に応じてこの動作をオーバーライドすることができる。

コード:(以前のソリューションと追加のnoScrollオプション)

  // hack to scroll to top when navigating to new URLS but not back/forward
  let wrap = function(method) {
    let orig = $window.window.history[method];
    $window.window.history[method] = function() {
      let retval = orig.apply(this, Array.prototype.slice.call(arguments));
      if($state.current && $state.current.noScroll) {
        return retval;
      }
      $anchorScroll();
      return retval;
    };
  };
  wrap('pushState');
  wrap('replaceState');

それをapp.runブロックに入れ、$state...を注入します。myApp.run(function($state){...})

次に、ページの一番上までスクロールしたくない場合は、次のようなルートを作成してください。

.state('someState', {
  parent: 'someParent',
  url: 'someUrl',
  noScroll : true // Notice this parameter here!
})
0
Augie Gardner