it-swarm.com.ru

Изменение маршрута не прокручивается вверх на новой странице

Я обнаружил какое-то нежелательное, по крайней мере для меня, поведение при изменении маршрута. На шаге 11 урока http://angular.github.io/angular-phonecat/step-11/app/#/phones вы можете увидеть список телефонов. Если вы прокрутите вниз и нажмете на одну из последних, вы увидите, что прокрутка не сверху, а скорее посередине.

Я также нашел это в одном из своих приложений, и мне было интересно, как я могу получить это, чтобы прокрутить вверх. Я могу сделать это вручную, но я думаю, что должен быть другой элегантный способ сделать это, которого я не знаю.

Итак, есть ли элегантный способ прокрутки вверх при изменении маршрута?

270
Matias Gonzalez

Проблема в том, что ваш ngView сохраняет позицию прокрутки при загрузке нового представления. Вы можете указать $anchorScroll «прокручивать область просмотра после обновления представления» ( документы немного расплывчаты, но здесь прокрутка означает прокрутка к началу нового представления).

Решением является добавление autoscroll="true" к вашему элементу ngView:

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

Просто поместите этот код для запуска

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

    window.scrollTo(0, 0);

});
44
xmaster

Этот код отлично сработал для меня ... Надеюсь, он также сработает отлично для вас .. Все, что вам нужно сделать, это просто вставить $ anchorScroll в ваш блок run и применить функцию слушателя к rootScope, как я это делал ниже пример .. 

 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 выполняются после создания инжектора и используются для запуска приложения. Это означает, что при перенаправлении на новое представление маршрута прослушиватель в блоке run вызывает 

$ AnchorScroll ()

и теперь вы можете видеть, что прокрутка начинается сверху с новым перенаправленным видом :)

35
Rizwan Jamal

После часа или двух попыток каждой комбинации ui-view autoscroll=true, $stateChangeStart, $locationChangeStart, $uiViewScrollProvider.useAnchorScroll(), $provide('$uiViewScroll', ...) и многих других я не смог заставить прокрутку вверх на новую страницу работать так, как ожидалось.

Это было в конечном счете, что работало для меня. Он захватывает 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 Я обнаружил, что функция автопрокрутки не имеет никакого эффекта, независимо от того, установлено ли значение true или false.

18
James

Используя Angularjs UI Router, я делаю так:

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

С:

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

Это никогда не терпит неудачу на любой странице, и это не глобально.

15
Léon Pelletier

FYI для тех, кто сталкивается с проблемой, описанной в названии (как и я), кто также использует Плагин AngularUI Router ...

В ответ на этот SO вопрос и ответ на этот вопрос маршрутизатор angular-ui переходит к нижней части страницы при изменении маршрутов.
Не можете понять, почему страница загружается внизу? Автопрокрутка углового UI-Router Выпуск

Однако, как говорится в ответе, вы можете отключить это поведение, сказав 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

Установка автопрокрутки в 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, используя описанные выше приемы. Но я думаю, что большинство людей захотят прокрутить всю страницу, если вы переходите на страницу как «новую».

Выше используется ui-router, хотя вместо этого вы можете использовать ng-route, поменяв местами $routeChangeSuccess на$stateChangeSuccess.

2
Dev93

Простое решение, добавьте scrollPositionRestoration в основной модуль маршрута включен.
Как это:

const routes: Routes = [

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

 @NgModule({
  imports: [
   RouterModule.forRoot(routes,{scrollPositionRestoration:'enabled'})
  ],
 exports: [
 RouterModule
 ]
 })
  export class AppRoutingModule { }
1
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