Rotayı değiştirmek yeni sayfada en üste gitmiyor


271

En azından benim için rota değiştiğinde bazı istenmeyen davranışlar buldum. Öğreticinin 11. adımında http://angular.github.io/angular-phonecat/step-11/app/#/phones telefonların listesini görebilirsiniz. En alta kaydırır ve en sonunculardan birine tıklarsanız, kaydırmanın en üstte olmadığını, ortada bir çeşit olduğunu görebilirsiniz.

Bunu uygulamalarımdan birinde de buldum ve üste kaydırmak için bunu nasıl elde edebileceğimi merak ediyordum. Bunu tek başına yapabilirim, ama bunu bilmem için başka zarif bir yol olması gerektiğini düşünüyorum.

Peki, rota değiştiğinde en üste kaydırmanın zarif bir yolu var mı?

Yanıtlar:


578

Sorun, ngView'ınızın yeni bir görünüm yüklediğinde kaydırma konumunu korumasıdır . $anchorScroll"Görünüm güncellendikten sonra görünüm penceresini kaydır" talimatını verebilirsiniz ( dokümanlar biraz belirsizdir, ancak buraya kaydırmak yeni görünümün en üstüne kaydırmak anlamına gelir ).

Çözüm , autoscroll="true"ngView öğenize eklemektir:

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

1
Bu iş benim için, sayfa yukarı ince kaydırma, ama ben smoothScroll yönergesi ile scrollTo kullanıyorum, üste bir smoth kaydırma yapmanın bir yolu var mı?, Ayrıca çözüm kaydırma sayfaya gitmek için görünümün üstüne kaydırmak için vardır sayfanın en üstünde?
xzegga

19
Dokümanlar durumu Özellik değer olmadan ayarlanmışsa, kaydırmayı etkinleştirin . Böylece kodu tam olarak kısaltabilirsiniz <div class="ng-view" autoscroll></div>ve aynı şekilde çalışır (kaydırma koşullu yapmak istemiyorsanız).
Daniel Liuzzi

7
benim için işe yaramıyor, doktor üste
kayacağını söylemiyor

6
Otomatik kaydırma doğru olarak ayarlanırsa, bir kullanıcı 'geri döndüğünde' sayfanın üst kısmına döndüğünü, bıraktığı yere değil, istenmeyen bir davranış olduğunu görüyorum.
axzr

4
bu, görünümünüzü bu div'e kaydırır. Böylece sayfanın üst kısmına yalnızca sayfanın üst kısmındaysa kaydırılır. Aksi takdirde $window.scrollTo(0,0)$ stateChangeSuccess olay dinleyicisinde koşmanız gerekecek
Filip Sobczak

46

Sadece bu kodu çalıştır

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

    window.scrollTo(0, 0);

});

6
$window.scrollTop(0,0)benim için otomatik kaydırmadan daha iyi çalışır. Benim durumumda geçişlerle giren ve çıkan görüşlere sahibim.
IsidroGH

1
Bu benim için autoscroll = "true" dan daha iyi çalışıyor. Otomatik kaydırma bir nedenden ötürü çok geç kalmıştır, yeni görünüm zaten göründükten sonra en üste kayar.
Gregory Bolkenstijn

5
Bu benim için en iyi sonucu verdi: $ rootScope. $ On ('$ stateChangeSuccess', function () {$ ("html, body"). Animate ({scrollTop: 0}, 200);});
James Gentes

$ window.scrollTop $ window.scrollTo olmalıdır, aksi takdirde var olmadığını söyler. Bu çözüm harika çalışıyor!
Yazılım Peygamberleri

@ JamesGentes de buna ihtiyacım vardı. Teşekkürler.
Mackenzie Browne

36

Bu kod benim için harika çalıştı .. Umarım sizin için de harika çalışır .. Tek yapmanız gereken $ anchorScroll komutunu çalıştırmak ve aşağıdaki örnekte yaptığım gibi rootScope'a dinleyici işlevi uygulamak ..

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

İşte Angularjs Modülünün arama sırası:

  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)

Enjektör oluşturulduktan sonra RUN BLOCK çalıştırılır ve uygulamayı başlatmak için kullanılır .. yeni rota görünümüne yönlendirdiğinizde, run bloğundaki dinleyici

$ AnchorScroll ()

ve şimdi yeni yönlendirilmiş görünümle kaydırma başlangıcında başlıyor görebilirsiniz :)


Son olarak, yapışkan başlıklarla çalışan bir çözüm! Teşekkür ederim!
Fabio

31

Her birleşimini çalışmakla bir iki saat sonra ui-view autoscroll=true, $stateChangeStart, $locationChangeStart, $uiViewScrollProvider.useAnchorScroll(), $provide('$uiViewScroll', ...)beklendiği gibi, ve diğerleri, ben kaydırma-to-top-on-yeni-sayfa çalışmalarına alamadım.

Sonuçta benim için işe yarayan buydu. PushState ve replaceState'i yakalar ve yalnızca yeni sayfalara yönlendirildiğinde kaydırma konumunu günceller (geri / ileri düğmesi kaydırma konumlarını korur):

.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');
})

Bu benim kullanım durumum için harika çalışıyor. İç içe görünümlerle (birkaç düzey derinliğinde) Açısal UI-Router kullanıyorum. Teşekkürler!
Joshua Powell

FYI - pushState'i kullanmak için açısal olarak HTML5 modunda olmanız gerekir: $locationProvider.html5Mode(true); @wkronkel, açısal olarak HTML5 modunu kullanmadığınızda bunu başarmanın bir yolu var mı? Neden html 5 modunun aktif olması nedeniyle sayfa yeniden yüklenmesi 404 hatası atıyor
britztopher

@britztopher Yerleşik etkinliklere bağlanabilir ve kendi geçmişinizi koruyabilirsiniz, değil mi?
Casey

2
bunu nereye ekliyorsun .run? açısal appnesneniz?
Philll_t

1
@Philll_t: Evet, runişlev her açısal modül nesnesinde bulunan bir yöntemdir.
Hinrich

18

İşte (görünüşte) sağlam, eksiksiz ve (oldukça) özlü çözümüm. Minimasyon uyumlu stili (ve modülünüze angular.module (NAME) erişimini) kullanır.

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

PS: Otomatik kaydırma işleminin doğru veya yanlış olarak ayarlanmış herhangi bir etkisi olmadığını buldum.


1
Hmmm .. bu parşömenler üstüne görünümü ilk ve sonra benim için ekranda görünümü değişir.
Strelok

Aradığım temiz çözüm. "Geri" yi tıklatırsanız sizi kaldığınız yere götürür - bu bazıları için arzu edilmeyebilir, ancak benim durumumda beğendim.
mjoyce91

15

Angularjs UI Router kullanarak, yaptığım bu:

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

İle:

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

Hiçbir sayfada başarısız olmaz ve global değildir.


1
Harika bir fikir, kullanarak daha kısa yapabilirsiniz:onEnter: scrollContent
zucker

2
Yazdığınız yere ne koydunuz // Your favorite scroll method here?
Ajan Zebra

4
İyi zamanlama: Orijinal kodda bu yorumun üstünde iki satır vardı, ui-router-title çalışıyor . Kullandığım $('html, body').animate({ scrollTop: -10000 }, 100);
Léon Pelletier

1
Haha, harika! Tuhaf tho, benim için her zaman işe yaramıyor. Ben bir kaydırma yok çok kısa bazı görünümleri ve bir kaydırma var iki görünüm var, ben onEnter: scrollContenther görünümü yerleştirdiğinizde sadece ilk görünüm / rota üzerinde değil, 2. bir çalışır. Garip.
Ajan Zebra

1
Emin değilim, hayır, Sadece gerektiğinde yukarı kaymaz. 'Güzergahlar' arasında tıkladığımda, bazıları hala ekteki sayfanın mutlak üstü yerine ng-görünümünün bulunduğu yere ilerliyor. bu mantıklı mı?
Ajan Zebra

13

AngularUI Router'ı da kullanan başlıkta açıklanan problemle karşılaşan herkes için FYI eklentisini ...

Bu SO sorusunda sorulduğu ve yanıtlandığı gibi, rotaları değiştirdiğinizde açısal-ui yönlendirici sayfanın altına atlar.
Sayfanın neden altta yüklendiğini bulamıyor musunuz? Açısal UI-Router otomatik kaydırma Sorunu

Cevap devletler olarak Ancak, diyerek bu davranışı kapatabilirsiniz autoscroll="false"Aşağıdaki yerlerde de ui-view.

Örneğin:

<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


16
Benimki aşağıya atlamıyor, sadece yukarı çıkmak yerine kaydırma konumunu koruyor.
Stephen Smith

5
Bu soruya cevap vermiyor. Aynı problemim var - rota değiştiğinde kaydırma seviyesi sadece yukarı kaydırmak yerine aynı yerde kalır. En üste kaydırmayı sağlayabilirim, ancak sadece bariz nedenlerle yapmak istemediğim karma değerini değiştirerek.
Will

7

bu javascript'i kullanabilirsiniz

$anchorScroll()

3
Angularjs'de o kadar basit değil. Çözümünüz yalnızca jquery'de geçerlidir. Aradığım şey bunu angularjs'de yapmanın zarif bir yoludur
Matias Gonzalez

4
$ AnchorScroll () kullanmayı denediniz mi, docs.angularjs.org/api/ng.%24anchorScroll olarak belgelenmiştir .
CodeIsLife

1
FYI Varsayılan ileri / geri tarayıcı düğmelerinden $location.hash('top')önce $anchorScroll()olan bir konum belirtirseniz, artık çalışmaz; sizi URL'deki karmaya yönlendiriyorlar
Roy

7

Ui-yönlendirici kullanıyorsanız (çalışma sırasında) kullanabilirsiniz

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

Bu çalışması gerektiğini biliyorum, ben yaygın olarak "$ stateChangeSuccess" kullanıyorum, ama nedense $ window.scrollTo (0,0) bununla çalışmıyor.
Abhas

4

Bu çözümü buldum. Yeni bir görünüme giderseniz işlev yürütülür.

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

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

3

AutoScroll öğesini true olarak ayarlamak benim için hile yapmadı, bu yüzden başka bir çözüm seçtim. Rotanın değiştiği her seferinde çengel olan ve en üste kaydırmak için yerleşik $ anchorScroll hizmetini kullanan bir hizmet oluşturdum. Benim için çalışıyor :-).

Hizmet:

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

Kayıt:

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

3

Partiye biraz geç kaldım, ama olası her yöntemi denedim ve hiçbir şey düzgün çalışmadı. İşte benim zarif çözümüm:

Tüm sayfalarımı ui-yönlendirici ile yöneten bir denetleyici kullanıyorum. Kimliği doğrulanmayan veya doğrulanmayan kullanıcıları uygun bir konuma yönlendirmeme olanak tanır. Çoğu insan ara katmanlarını uygulamalarının yapılandırmasına koydu, ancak bazı http isteklerine ihtiyacım vardı, bu nedenle genel bir denetleyici benim için daha iyi çalışıyor.

Benim index.html şöyle görünür:

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

Benim initCtrl.js şöyle görünüyor:

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

Olası her seçeneği denedim, bu yöntem en iyi sonucu veriyor.


1
Benim için açısal malzeme ile çalışan tek şey bu, aynı zamanda id="top-nav"doğru elemanı yerleştirmek de önemliydi.
BatteryAcid

2

Yukarıdaki yanıtların tümü beklenen tarayıcı davranışını kırıyor. Çoğu insanın istediği şey, "yeni" bir sayfa ise en üste kaydırılacak, ancak Geri (veya İleri) düğmesinden geçiyorsanız önceki konuma geri dönecek bir şeydir.

HTML5 modunu varsayarsanız, bu kolay olur (ancak bazı parlak insanlar bunu nasıl daha zarif hale getirebileceğinden emin olabilirim!):

// 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;
}

Çalışma şekli, yönlendiricinin en üste kaydırılacağını varsayar, ancak tarayıcıya bitirme şansı vermek için biraz geciktirir. Tarayıcı daha sonra değişikliğin Geri / İleri gezinme nedeniyle olduğunu bildirirse, zaman aşımını iptal eder ve kaydırma hiçbir zaman gerçekleşmez.

documentKaydırma yapmak için ham komutları kullandım çünkü pencerenin en üstüne gitmek istiyorum. Sadece ui-viewkaydırmak istiyorsanız, yukarıdaki teknikleri kullanarak autoscroll="my_var"nerede kontrol edeceğinizi ayarlayın my_var. Ancak, sayfaya "yeni" olarak gidiyorsanız, çoğu insan tüm sayfayı kaydırmak isteyeceğini düşünüyorum.

Yukarıdaki kullanımların ui-yönlendirici, size rağmen yerine değiştirerek ng-rota kullanabilirsiniz $routeChangeSuccessiçin $stateChangeSuccess.


Bunu nasıl uyguluyorsunuz? Aşağıdaki gibi normal açısal-ui yolları koduna nereye koyardınız? var routerApp = angular.module('routerApp', ['ui.router']); routerApp.config(function($stateProvider, $urlRouterProvider, $locationProvider) { $urlRouterProvider.otherwise('/home'); $locationProvider.html5Mode(false).hashPrefix(""); $stateProvider // HOME STATES AND NESTED VIEWS ======================================== .state('home', { url: '/home', templateUrl: 'partial-home.html' }) });
Ajan Zebra

hmmm ... işe yaramadı :-( Sadece uygulamayı öldürür.Bu sadece bir .state('web', { url: '/webdev', templateUrl: 'partial-web.html', controller: function($scope) { $scope.clients = ['client1', 'client2', 'client3']; // I put it here } }) şeyler öğreniyorum, belki bir şey eksik: D
Ajan Zebra

@AgentZebra En azından, denetleyicinin giriş olarak $ zaman aşımı alması gerekecek (kodum referans verdiği için), ancak belki de daha önemlisi, bahsettiğim denetleyicinin bireysel bir durumun ( ifadeleri üst düzey denetleyicinize ekleyebilir). İlk AngularJS öğrenme eğrisi gerçekten çok zordur; iyi şanslar!
Dev93

2

Verilen cevapların hiçbiri sorunumu çözmedi. Görünümler arasında bir animasyon kullanıyorum ve kaydırma her zaman animasyondan sonra gerçekleşecekti. Animasyondan önce en üste kaydırmanın aşağıdaki yönerge olması için bulduğum çözüm:

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

            })
        }
    };
}]);

Benim görüşüme aşağıdaki gibi ekledim:

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

2

Basit Çözüm, scrollPositionRestorationetkinleştirilmiş ana rota modülüne ekleyin .
Bunun gibi:

const routes: Routes = [

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

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


0

Sonunda ihtiyacım olanı aldım.

Yukarı kaydırmak zorunda kaldım, ancak bazı geçişlerin

Bunu rota-rota düzeyinde kontrol edebilirsiniz.
@Wkonkel tarafından yukarıdaki çözümü birleştiriyorum ve basit birnoScroll: true bazı rota bildirimlerine parametre . Sonra bunu geçişte yakalıyorum.

Sonuçta: Bu, yeni geçişlerde sayfanın üst kısmına yüzer, üstteki geçişlere Forward/ Backgeçişlere sığmaz ve gerekirse bu davranışı geçersiz kılmanıza olanak tanır.

Kod: (önceki çözüm artı ekstra noScroll seçeneği)

  // 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');

Bunu app.runbloğuna koy ve enjekte et $state...myApp.run(function($state){...})

Ardından, sayfanın en üstüne kaydırmak istemiyorsanız, aşağıdaki gibi bir rota oluşturun:

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

0

Bu otomatik kaydırma dahil benim için çalıştı

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.