Как обрабатывать привязку привязки привязки в AngularJS

Кто-нибудь из вас знает, как хорошо обрабатывать привязку привязки привязки в AngularJS?

У меня есть следующая разметка для простой часто задаваемой страницы

<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 +, поэтому я боюсь, что это не принятое решение:/

Ответ 1

Вы ищете $anchorScroll().

Здесь (дерьмовая) документация.

И вот источник.

В основном вы просто вводите его и вызываете его в своем контроллере, и он будет прокручивать вас до любого элемента с идентификатором, найденным в $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>

Здесь показан плункер.

EDIT: использовать это с маршрутизацией

Настройте свою маршрутизацию 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>

Вот Plunker, демонстрирующий прокрутку с маршрутизацией и $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>

Ответ 2

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

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

Ответ 3

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

И используйте атрибут id в html:

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

Нет необходимости использовать ## как указано/упомянуто в комментариях; -)

Ответ 4

<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="faq-3">Question 3</h3>

Ответ 5

Если вы всегда знаете маршрут, вы можете просто добавить якорь следующим образом:

href="#/route#anchorID

где route - текущий маршрут angular, а anchorID соответствует <a id="anchorID"> где-то на странице

Ответ 6

Это было мое решение, используя директиву, которая выглядит больше Angular -y, потому что мы имеем дело с DOM:

Plnkr здесь

github

CODE

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-коммутатору, и обновления обновили бы приложение.

Ответ 7

$anchorScroll работает для этого, но есть гораздо лучший способ использовать его в более поздних версиях Angular.

Теперь $anchorScroll принимает хеш в качестве необязательного аргумента, поэтому вам не нужно вообще менять $location.hash. (документация)

Это лучшее решение, потому что оно вообще не влияет на маршрут. Я не мог заставить любое другое решение работать, потому что я использую ngRoute, и маршрут будет перезагружаться, как только я установлю $location.hash(id), прежде чем $anchorScroll сможет сделать свою магию.

Вот как его использовать... во-первых, в директиве или контроллере:

$scope.scrollTo = function (id) {
  $anchorScroll(id);  
}

а затем в представлении:

<a href="" ng-click="scrollTo(id)">Text</a>

Кроме того, если вам нужно учесть фиксированный navbar (или другой пользовательский интерфейс), вы можете установить смещение для $anchorScroll как это (в функции запуска основного модуля):

.run(function ($anchorScroll) {
   //this will make anchorScroll scroll to the div minus 50px
   $anchorScroll.yOffset = 50;
});

Ответ 8

Попробуйте установить префикс хеша для angular маршрутов $locationProvider.hashPrefix('!')

Полный пример:

angular.module('app', [])
  .config(['$routeProvider', '$locationProvider', 
    function($routeProvider, $locationProvider){
      $routeProvider.when( ... );
      $locationProvider.hashPrefix('!');
    }
  ])

Ответ 9

Я обошел это в логике маршрутов для своего приложения.

function config($routeProvider) {
  $routeProvider
    .when('/', {
      templateUrl: '/partials/search.html',
      controller: 'ctrlMain'
    })
    .otherwise({
      // Angular interferes with anchor links, so this function preserves the
      // requested hash while still invoking the default route.
      redirectTo: function() {
        // Strips the leading '#/' from the current hash value.
        var hash = '#' + window.location.hash.replace(/^#\//g, '');
        window.location.hash = hash;
        return '/' + hash;
      }
    });
}

Ответ 10

Это старый пост, но я долгое время изучал различные решения, поэтому хотел поделиться еще одним простым. Просто добавив target="_self" в тег <a>, исправил его для меня. Ссылка работает и возвращает меня в нужное место на странице.

Тем не менее, Angular все еще вводит какую-то странность С# в URL-адресе, поэтому вы можете столкнуться с трудностями с помощью кнопки "Назад" для навигации и после этого этого метода.

Ответ 11

Это может быть новый атрибут для ngView, но мне удалось привязать хэш-ссылки для работы с angular-route с помощью атрибута ngView autoscroll и "double-hashes".

ngView (см. autoscroll)

(Следующий код использовался с angular -strap)

<!-- use the autoscroll attribute to scroll to hash on $viewContentLoaded -->    
<div ng-view="" autoscroll></div>

<!-- A.href link for bs-scrollspy from angular-strap -->
<!-- A.ngHref for autoscroll on current route without a location change -->
<ul class="nav bs-sidenav">
  <li data-target="#main-html5"><a href="#main-html5" ng-href="##main-html5">HTML5</a></li>
  <li data-target="#main-angular"><a href="#main-angular" ng-href="##main-angular" >Angular</a></li>
  <li data-target="#main-karma"><a href="#main-karma" ng-href="##main-karma">Karma</a></li>
</ul>

Ответ 12

Я мог бы сделать это так:

<li>
<a href="#/#about">About</a>
</li>

Ответ 13

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

Ответ 14

Моим решением с 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>

Ответ 15

Вы можете попытаться использовать 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>

... и не секрет для идентификатора привязки:

<div id="foo">
  This is #foo
</div>

Ответ 16

Я не уверен на 100%, если это работает все время, но в моем приложении это дает мне ожидаемое поведение.

Предположим, вы находитесь на странице О, и у вас есть следующий маршрут:

yourApp.config(['$routeProvider', 
    function($routeProvider) {
        $routeProvider.
            when('/about', {
                templateUrl: 'about.html',
                controller: 'AboutCtrl'
            }).
            otherwise({
                redirectTo: '/'
            });
        }
]);

Теперь вы в HTML

<ul>
    <li><a href="#/about#tab1">First Part</a></li>
    <li><a href="#/about#tab2">Second Part</a></li>
    <li><a href="#/about#tab3">Third Part</a></li>                      
</ul>

<div id="tab1">1</div>
<div id="tab2">2</div>
<div id="tab3">3</div>

В заключение

Включение имени страницы перед тем, как якорь помогло. Дайте мне знать о ваших мыслях.

Даунсайд

Это приведет к повторному отображению страницы, а затем прокрутку к якорю.

UPDATE

Лучше всего добавить следующее:

<a href="#tab1" onclick="return false;">First Part</a>

Ответ 17

<a href="/#/#faq-1">Question 1</a>
<a href="/#/#faq-2">Question 2</a>
<a href="/#/#faq-3">Question 3</a>

Ответ 18

Получить прокрутку. Он также поддерживает Анимированную/Гладкую прокрутку в качестве дополнительной функции. Подробная информация для Angular Библиотека прокрутки:

Github - https://github.com/oblador/angular-scroll

Бауэр: bower install --save angular-scroll

npm: npm install --save angular-scroll

Minfied version - только 9kb

Плавная прокрутка (анимированная прокрутка) - да

Scroll Spy - да

Документация - отлично

Демо - http://oblador.github.io/angular-scroll/

Надеюсь, что это поможет.

Ответ 19

Если вы не любите использовать 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;
    };
}])

Ответ 20

Я пытался сделать мое приложение Angular прокруткой к загрузке якоря opon и столкнулось с правилами перезаписи URL-адреса $routeProvider.

После долгих экспериментов я остановился на этом:

  • зарегистрировать обработчик события document.onload из раздела .run() модуль приложения Angular.
  • в обработчике узнать, что оригинал Предполагается, что якорный тег должен выполняться строковыми операциями.
  • переопределить 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();
			}
		}	 
 });

Ответ 21

При изменении маршрута он будет прокручиваться до верхней части страницы.

 $scope.$on('$routeChangeSuccess', function () {
      window.scrollTo(0, 0);
  });

поместите этот код на свой контроллер.

Ответ 22

В моем уме @slugslog имел это, но я бы изменил одно. Я бы использовал вместо этого замену, поэтому вам не нужно ее возвращать.

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

Docs Поиск "Заменить метод"

Ответ 23

Ни одно из вышеперечисленных решений не работает для меня, но я просто попробовал это, и это сработало,

<a href="#/#faq-1">Question 1</a>

Итак, я понял, что мне нужно уведомить страницу, чтобы начать с индексной страницы, а затем использовать традиционный якорь.

Ответ 24

Я использую AngularJS 1.3.15 и, похоже, мне не нужно ничего особенного.

https://code.angularjs.org/1.3.15/docs/api/ng/provider/ $anchorScrollProvider

Итак, для меня в моем html работает следующее:

<ul>
  <li ng-repeat="page in pages"><a ng-href="#{{'id-'+id}}">{{id}}</a>
  </li>
</ul>
<div ng-attr-id="{{'id-'+id}}" </div>

Мне не пришлось вообще вносить какие-либо изменения в мой контроллер или JavaScript.

Ответ 25

Когда-то в angularjs приложение hash navigation не работает, а javascript-библиотеки bootstrap javascript широко используют этот тип навигации, чтобы заставить его работать, добавляя target="_self" к тегу привязки. например <a data-toggle="tab" href="#id_of_div_to_navigate" target="_self">

Ответ 26

См. https://code.angularjs.org/1.4.10/docs/api/ngRoute/provider/ $routeProvider

[reloadOnSearch = true] - {boolean =} - перезагрузить маршрут, когда изменяются только $location.search() или $location.hash().

Установка этого значения в false сделала трюк без всего вышеперечисленного для меня.