J'ai trouvé un comportement indésirable, du moins pour moi, lorsque la route change . À l'étape 11 du tutoriel http://angular.github.io/angular-phonecat/step-11/app/ #/phones vous pouvez voir la liste des téléphones. Si vous faites défiler vers le bas et cliquez sur l'une des dernières, vous pouvez voir que le défilement n'est pas en haut, mais plutôt au milieu.
Je l'ai aussi trouvé dans l'une de mes applications et je me demandais comment puis-je le faire défiler vers le haut. Je peux le faire manuellement, mais je pense qu'il devrait exister une autre manière élégante de le faire que je ne connais pas.
Alors, y a-t-il un moyen élégant de faire défiler vers le haut lorsque la route change?
Le problème est que votre ngView conserve la position de défilement lorsqu'il charge une nouvelle vue. Vous pouvez demander à $anchorScroll
de "faire défiler la fenêtre une fois la vue mise à jour" (les -docs sont un peu vagues, mais faire défiler signifie ici faire défiler vers le haut de la nouvelle vue).
La solution consiste à ajouter autoscroll="true"
à votre élément ngView:
<div class="ng-view" autoscroll="true"></div>
Il suffit de mettre ce code à courir
$rootScope.$on("$routeChangeSuccess", function (event, currentRoute, previousRoute) {
window.scrollTo(0, 0);
});
Après une heure ou deux d'essayer toutes les combinaisons de ui-view autoscroll=true
, $stateChangeStart
, $locationChangeStart
, $uiViewScrollProvider.useAnchorScroll()
, $provide('$uiViewScroll', ...)
et de nombreux autres, je ne pouvais pas obtenir le défilement vers le haut de la nouvelle page pour fonctionner comme prévu.
C'était finalement ce qui a fonctionné pour moi. Il capture pushState et replaceState et ne met à jour que la position de défilement lorsque de nouvelles pages sont consultées (le bouton Précédent/Suivant conserve les positions de défilement):
.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');
})
Voici ma solution (apparemment) robuste, complète et (assez) concise. Il utilise le style compatible avec la minification (et l'accès angular.module (NAME) à votre module).
angular.module('yourModuleName').run(["$rootScope", "$anchorScroll" , function ($rootScope, $anchorScroll) {
$rootScope.$on("$locationChangeSuccess", function() {
$anchorScroll();
});
}]);
Post-scriptum j'ai trouvé que la chose autoscroll n'avait aucun effet si défini sur true ou false.
En utilisant angularjs UI Router, voici ce que je fais:
.state('myState', {
url: '/myState',
templateUrl: 'app/views/myState.html',
onEnter: scrollContent
})
Avec:
var scrollContent = function() {
// Your favorite scroll method here
};
Il n'échoue jamais sur aucune page, et ce n'est pas global.
Pour votre information, si vous rencontrez le problème décrit dans le titre (comme je le faisais) qui utilise également Le AngularUI Router plugin ...
Comme demandé et répondu à cette question SO, le routeur angular-ui passe au bas de la page lorsque vous modifiez les itinéraires.
Vous ne pouvez pas comprendre pourquoi la page se charge en bas? Problème de défilement automatique de routeur d'interface utilisateur angulaire
Toutefois, comme l'indique la réponse, vous pouvez désactiver ce comportement en indiquant autoscroll="false"
sur votre ui-view
.
Par exemple:
<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
vous pouvez utiliser ce javascript
$anchorScroll()
Si vous utilisez le routeur ui, vous pouvez utiliser (en marche)
$rootScope.$on("$stateChangeSuccess", function (event, currentState, previousState) {
$window.scrollTo(0, 0);
});
J'ai trouvé cette solution. Si vous accédez à une nouvelle vue, la fonction est exécutée.
var app = angular.module('hoofdModule', ['ngRoute']);
app.controller('indexController', function ($scope, $window) {
$scope.$on('$viewContentLoaded', function () {
$window.scrollTo(0, 0);
});
});
Un peu tard pour la fête, mais j'ai essayé toutes les méthodes possibles et rien ne fonctionnait correctement. Voici ma solution élégante:
J'utilise un contrôleur qui régit toutes mes pages avec ui-router. Cela me permet de rediriger les utilisateurs qui ne sont pas authentifiés ou validés vers un emplacement approprié. La plupart des gens ont mis leur middleware dans la configuration de leur application, mais j'avais besoin de quelques requêtes http. Par conséquent, un contrôleur global me convient mieux.
Mon index.html ressemble à:
<main ng-controller="InitCtrl">
<nav id="top-nav"></nav>
<div ui-view></div>
</main>
Mon initCtrl.js ressemble à:
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');
});
});
});
J'ai essayé toutes les options possibles, cette méthode fonctionne le mieux.
Définir autoScroll sur true ne me convenait pas, alors j'ai choisi une autre solution. J'ai créé un service qui prend en compte chaque changement d'itinéraire et qui utilise le service intégré $ anchorScroll pour faire défiler jusqu'en haut. Travaille pour moi :-).
Un service:
(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();
}
}
}());
Enregistrement:
angular.module("mymodule").run(["pageSwitch", function (pageSwitch) {
pageSwitch.registerListener();
}]);
Aucune des réponses fournies n'a résolu mon problème. J'utilise une animation entre les vues et le défilement aura toujours lieu après l'animation. La solution que j'ai trouvée pour que le défilement vers le haut se produise avant l'animation est la directive suivante:
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);
}
})
}
};
}]);
Je l'ai inséré dans ma vue comme suit:
<div scroll-to-top-before-animation>
<div ng-view class="view-animation"></div>
</div>
Toutes les réponses ci-dessus annulent le comportement attendu du navigateur. Ce que la plupart des gens veulent, c’est quelque chose qui fera défiler vers le haut s’il s’agit d’une «nouvelle» page, mais qui revient à la position précédente si vous y accédez par le bouton Précédent (ou Suivant).
Si vous supposez que le mode HTML5 est simple, cela s'avère facile (même si je suis sûr que certaines personnes brillantes peuvent comprendre comment rendre cela plus élégant!):
// 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;
}
La façon dont cela fonctionne est que le routeur suppose qu'il fera défiler vers le haut, mais attend un peu pour donner au navigateur une chance de finir. Si le navigateur nous informe ensuite que le changement est dû à une navigation Précédent/Suivant, il annule le délai et le défilement ne se produit jamais.
J'ai utilisé des commandes brutes document
pour faire défiler parce que je veux passer en haut de la fenêtre. Si vous souhaitez simplement que votre ui-view
défile, définissez autoscroll="my_var"
dans lequel vous contrôlez my_var
en utilisant les techniques ci-dessus. Mais je pense que la plupart des gens voudront faire défiler la page entière si vous allez sur la page en tant que "nouveau".
Ce qui précède utilise ui-router, bien que vous puissiez utiliser ng-route à la place en échangeant $routeChangeSuccess
pour$stateChangeSuccess
.
Solution simple, ajoutez scrollPositionRestoration
dans le module de route principale activé.
Comme ça:
const routes: Routes = [
{
path: 'registration',
loadChildren: () => RegistrationModule
},
];
@NgModule({
imports: [
RouterModule.forRoot(routes,{scrollPositionRestoration:'enabled'})
],
exports: [
RouterModule
]
})
export class AppRoutingModule { }
Essayez ceci http://ionicframework.com/docs/api/service/ $ ionicScrollDelegate /
Il fait défiler vers le haut de la liste scrollTop ()
Cela a fonctionné pour moi, y compris autoscroll
<div class="ngView" autoscroll="true" >
J'ai enfin obtenu ce dont j'avais besoin.
Je devais faire défiler vers le haut, mais je voulais certaines transitions ne pas à
Vous pouvez contrôler cela au niveau de chaque itinéraire.
Je combine la solution ci-dessus de @wkonkel et ajoute un simple paramètre noScroll: true
à certaines déclarations de route. Ensuite, je prends ça dans la transition.
Tout compte fait: Cela flotte en haut de la page sur les nouvelles transitions, il ne flotte pas en haut des transitions Forward
/Back
et vous permet de remplacer ce comportement si nécessaire.
Le code: (solution précédente plus une option supplémentaire 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');
Mettez cela dans votre bloc app.run
et injectez $state
... myApp.run(function($state){...})
Ensuite, si vous ne voulez pas faire défiler vers le haut de la page, créez un itinéraire comme celui-ci:
.state('someState', {
parent: 'someParent',
url: 'someUrl',
noScroll : true // Notice this parameter here!
})