I'm versuchen, eine schnelle nav zu bekommen, um richtig zu arbeiten. Es ist auf der Seite schwebend. Wenn sie auf einen Link klicken, werden sie zu dieser ID auf der Seite weitergeleitet. Ich folge dieser Anleitung von Treehouse. Dies ist, was ich für das Scrollen haben:
$("#quickNav a").click(function(){
var quickNavId = $(this).attr("href");
$("html, body").animate({scrollTop: $(location).offset().top}, "slow");
return false;
});
Ich habe es ursprünglich vor dem </body>
platziert. Aber ich scheine in eine Race Condition zu laufen, wo das vor dem quickNav kompiliert wurde (es hat ein "ng-hide" darauf platziert, nicht sicher, ob das es verursacht - aber es ist innerhalb des DOM) zu feuern.
Wenn ich diesen Codeblock in der Konsole ausführen, dann funktioniert das Scrollen wie erwartet.
Ich dachte, es wäre effektiver, dies in den Controller zu verschieben - oder eher in eine Direktive. Aber I'm nicht Glück haben, das zu erreichen. Wie kann ich diesen Codeblock mit AngularJS zum Laufen bringen?
Hier ist eine einfache Direktive, die bei einem Klick zu einem Element blättert:
myApp.directive('scrollOnClick', function() {
return {
restrict: 'A',
link: function(scope, $elm) {
$elm.on('click', function() {
$("body").animate({scrollTop: $elm.offset().top}, "slow");
});
}
}
});
Demo: http://plnkr.co/edit/yz1EHB8ad3C59N6PzdCD?p=preview
Hilfe bei der Erstellung von Direktiven finden Sie in den Videos auf http://egghead.io, beginnend mit #10 "erste Direktive".
Edit: Um zu einem bestimmten Element zu scrollen, das durch eine href angegeben ist, überprüfen Sie einfach attrs.href
.
myApp.directive('scrollOnClick', function() {
return {
restrict: 'A',
link: function(scope, $elm, attrs) {
var idToScroll = attrs.href;
$elm.on('click', function() {
var $target;
if (idToScroll) {
$target = $(idToScroll);
} else {
$target = $elm;
}
$("body").animate({scrollTop: $target.offset().top}, "slow");
});
}
}
});
Dann könnten Sie es so verwenden: <div scroll-on-click></div>
um zu dem angeklickten Element zu scrollen. Oder <a scroll-on-click href="#element-id"></div>
, um zum Element mit der id zu scrollen.
Dies ist eine bessere Richtlinie, falls Sie sie verwenden möchten:
Sie können zu jedem Element auf der Seite blättern:
.directive('scrollToItem', function() {
return {
restrict: 'A',
scope: {
scrollTo: "@"
},
link: function(scope, $elm,attr) {
$elm.on('click', function() {
$('html,body').animate({scrollTop: $(scope.scrollTo).offset().top }, "slow");
});
}
}})
Verwendung (z.B. Klick auf div 'back-to-top' scrollt zum id scroll-top):
<a id="top-scroll" name="top"></a>
<div class="back-to-top" scroll-to-item scroll-to="#top-scroll">
Es wird auch von Chrome, Firefox, Safari und IE unterstützt, da das Element html, body verwendet wird.
Danke Andy für das Beispiel, das war sehr hilfreich. Ich habe am Ende eine etwas andere Strategie implementiert, da ich einen einseitigen Bildlauf entwickle und nicht wollte, dass Angular bei Verwendung der Hashbang-URL aktualisiert. Ich möchte auch die Zurück/Vorwärts-Aktion des Browsers zu bewahren.
Anstatt die Direktive und den Hash zu verwenden, verwende ich ein $scope.$watch auf der $location.search und beziehe das Ziel von dort. Dies gibt eine schöne saubere Anker-Tag
<a ng-href="#/?scroll=myElement">Mein Element</a>
Ich habe den Watch-Code mit der Deklaration meines Moduls in app.js wie folgt verknüpft:
.run(function($location, $rootScope) {
$rootScope.$watch(function() { return $location.search() }, function(search) {
var scrollPos = 0;
if (search.hasOwnProperty('scroll')) {
var $target = $('#' + search.scroll);
scrollPos = $target.offset().top;
}
$("body,html").animate({scrollTop: scrollPos}, "slow");
});
})
Der Nachteil des obigen Codes ist, dass das DOM möglicherweise nicht rechtzeitig für den $target.offset()-Aufruf von jQuery geladen wird, wenn der Zugriff per URL direkt von einer anderen Route aus erfolgt. Die Lösung besteht darin, diesen Code in einem $viewContentLoaded Watcher zu verschachteln. Der endgültige Code sieht etwa so aus:
.run(function($location, $rootScope) {
$rootScope.$on('$viewContentLoaded', function() {
$rootScope.$watch(function() { return $location.search() }, function(search) {
var scrollPos = 0
if (search.hasOwnProperty('scroll')) {
var $target = $('#' + search.scroll);
var scrollPos = $target.offset().top;
}
$("body,html").animate({scrollTop: scrollPos}, "slow");
});
});
})
Getestet mit Chrome und FF