javascript - Cum să gestionezi linkurile cu hash de ancoră în AngularJS
Vreunul dintre voi știe cum să gestioneze frumos linkurile cu hash de ancoră în AngularJS?
Am următorul cod pentru o pagină simplă de întrebări frecvente
<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>
Când fac clic pe oricare dintre linkurile de mai sus, AngularJS interceptează și mă direcționează către o pagină complet diferită (în cazul meu, o pagină 404, deoarece nu există rute care să corespundă linkurilor).
Primul meu gând a fost să creez o rută care să se potrivească cu "/faq/:chapter" și în controller-ul corespunzător să verific $routeParams.chapter după un element potrivit și apoi să folosesc jQuery pentru a derula în jos până la acesta.
Dar apoi AngularJS mă tratează din nou prost și tot derulează înapoi în partea de sus a paginii.
Deci, cineva aici a mai făcut ceva similar în trecut și cunoaște o soluție bună pentru asta?
Editare: Trecerea la html5Mode ar trebui să îmi rezolve problemele, dar trebuie să suportăm IE8+ oricum, așa că mă tem că nu este o soluție acceptată :/
Răspuns #1
Cauți $anchorScroll().
Iată documentația (proastă).
Și iată sursa.
Practic, trebuie doar să-l injectezi și să-l apelezi în controller-ul tău, iar el te va derula la orice element cu id-ul găsit în $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>
Iată un plunker pentru a demonstra
EDITARE: pentru a folosi asta cu rutare
Configurează-ți rutarea Angular așa cum faci de obicei, apoi adaugă pur și simplu următorul cod.
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();
});
});
și linkul tău ar arăta astfel:
<a href="#/test?scrollTo=foo">Test/Foo</a>
Iată un Plunker care demonstrează derularea cu rutare și $anchorScroll
Și chiar mai simplu:
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();
});
});
și linkul tău ar arăta astfel:
<a href="#/test#foo">Test/Foo</a>
Răspunsul #2
În cazul meu, am observat că logica de rutare intervenea dacă modificam $location.hash(). Următorul truc a funcționat..
$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);
};
Răspunsul #3
Nu este nevoie să schimbați nicio rutare sau altceva, doar trebuie să folosiți target="_self" atunci când creați linkurile
Exemplu :
<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>
Și folosește atributul id în elementele tale html astfel:
<h3 id="faq-1">Question 1</h3>
<h3 id="faq-2">Question 2</h3>
<h3 id="faq-3">Question 3</h3>
Nu este nevoie să folosești ## așa cum s-a indicat/menționat în comentarii ;-)
Răspunsul #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>
Răspunsul #5
Dacă știi întotdeauna ruta, poți pur și simplu să adaugi ancora astfel:
href="#/route#anchorID
unde route este ruta curentă Angular și anchorID corespunde unui <a id="anchorID"> undeva pe pagină
Răspunsul #6
$anchorScroll funcționează pentru aceasta, dar există o metodă mult mai bună de a-l folosi în versiunile mai recente de Angular.
Acum, $anchorScroll acceptă hash-ul ca argument opțional, deci nu trebuie să schimbați deloc $location.hash. (documentație)
Aceasta este cea mai bună soluție deoarece nu afectează deloc ruta. Nu am reușit să fac să funcționeze niciuna dintre celelalte soluții pentru că folosesc ngRoute și ruta s-ar reîncărca imediat ce setez $location.hash(id), înainte ca $anchorScroll să-și facă magia.
Iată cum să-l folosești... mai întâi, în directivă sau în controler:
$scope.scrollTo = function (id) {
$anchorScroll(id);
}
și apoi în vedere:
<a href="" ng-click="scrollTo(id)">Text</a>
De asemenea, dacă trebuie să ții cont de o bară de navigare fixă (sau alt UI), poți seta decalajul pentru $anchorScroll astfel (în funcția run a modulului principal):
.run(function ($anchorScroll) {
//this will make anchorScroll scroll to the div minus 50px
$anchorScroll.yOffset = 50;
});
Răspunsul #7
Aceasta a fost soluția mea folosind o directivă care pare mai în stil Angular deoarece lucrăm cu DOM-ul:
Plnkr aici
github
COD
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>
Am folosit serviciul $anchorScroll. Pentru a contracara reîmprospătarea paginii care apare odată cu schimbarea hash-ului, am anulat evenimentul locationChangeStart. Acest lucru a funcționat pentru mine deoarece aveam o pagină de ajutor conectată la un ng-switch și reîmprospătările ar fi întrerupt practic aplicația.
