javascript - div - Función ScrollTo en AngularJS
scroll to div angularjs (9)
Estoy tratando de obtener una navegación rápida para que funcione correctamente. Está flotando en el costado. Cuando hacen clic en un enlace, los lleva a esa ID en la página. Estoy siguiendo esta guía desde Treehouse . Esto es lo que tengo para el desplazamiento:
$("#quickNav a").click(function(){
var quickNavId = $(this).attr("href");
$("html, body").animate({scrollTop: $(location).offset().top}, "slow");
return false;
});
Inicialmente lo coloqué antes del </body>
. Pero parece que me encuentro en una condición de carrera en la que se estaba disparando antes de compilar quickNav (tiene un ng-hide
colocado, no estoy seguro de si eso está causando, pero está dentro del DOM).
Si ejecuto ese bloque de código en la consola, entonces el desplazamiento funciona como se esperaba.
Pensé que sería más efectivo mover esto al controlador, o más probablemente dentro de una directiva. Pero no estoy teniendo suerte logrando eso. ¿Cómo puedo hacer que este bloque de código funcione con AngularJS?
¿Qué pasa angular-scroll , se mantiene activamente y no hay dependencia de jQuery ...
Aquí hay una directiva simple que se desplazará a un elemento al hacer clic:
myApp.directive(''scrollOnClick'', function() {
return {
restrict: ''A'',
link: function(scope, $elm) {
$elm.on(''click'', function() {
$("body").animate({scrollTop: $elm.offset().top}, "slow");
});
}
}
});
Demostración: http://plnkr.co/edit/yz1EHB8ad3C59N6PzdCD?p=preview
Para obtener ayuda sobre cómo crear directivas, consulte los videos en http://egghead.io , comenzando con la # 10 "primera directiva".
editar : para hacer que se desplace a un elemento específico especificado por un href, simplemente marque 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");
});
}
}
});
Entonces podría usarlo así: <div scroll-on-click></div>
para desplazarse al elemento al que se hace clic. O bien, <a scroll-on-click href="#element-id"></div>
para desplazarse al elemento con el id.
Esta es una directiva mejor en caso de que quiera usarla:
puede desplazarse a cualquier elemento en la página:
.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");
});
}
}})
Uso (por ejemplo, haga clic en div ''back-to-top'' se desplazará a id scroll-top):
<a id="top-scroll" name="top"></a>
<div class="back-to-top" scroll-to-item scroll-to="#top-scroll">
También es compatible con Chrome, Firefox, Safari y IE causa del html, elemento del cuerpo.
Gracias Andy por el ejemplo, esto fue muy útil. Terminé implementando una estrategia ligeramente diferente ya que estoy desarrollando un desplazamiento de página única y no quería que Angular se actualizara cuando usaba la URL de hashbang. También quiero preservar la acción de retroceso / avance del navegador.
En lugar de usar la directiva y el hash, estoy usando $ scope. $ Watch en $ location.search y obtengo el objetivo desde allí. Esto da una buena etiqueta de anclaje limpio
<a ng-href="#/?scroll=myElement">My element</a>
Encadené el código del reloj a la declaración de mi módulo en app.js, así:
.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");
});
})
La advertencia con el código anterior es que si accede por URL directamente desde una ruta diferente, el DOM no se puede cargar a tiempo para la llamada $ target.offset () de jQuery. La solución es anidar este código dentro de un vigilante $ viewContentLoaded. El código final se ve así:
.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");
});
});
})
Probado con Chrome y FF
Otra sugerencia Una directiva con selector.
HTML:
<button type="button" scroll-to="#catalogSection">Scroll To</button>
Angular:
app.directive(''scrollTo'', function () {
return {
restrict: ''A'',
link: function (scope, element, attrs) {
element.on(''click'', function () {
var target = $(attrs.scrollTo);
if (target.length > 0) {
$(''html, body'').animate({
scrollTop: target.offset().top
});
}
});
}
}
});
También note $anchorScroll
Para animar a un elemento específico dentro de un contenedor de desplazamiento (DIV fijo)
/*
@param Container(DIV) that needs to be scrolled, ID or Div of the anchor element that should be scrolled to
Scrolls to a specific element in the div container
*/
this.scrollTo = function(container, anchor) {
var element = angular.element(anchor);
angular.element(container).animate({scrollTop: element.offset().top}, "slow");
}
Una solución angular que usa $ anchorScroll http://www.benlesh.com/2013/02/angular-js-scrolling-to-element-by-id.html :
app.controller(''MainCtrl'', function($scope, $location, $anchorScroll) {
var i = 1;
$scope.items = [{ id: 1, name: ''Item 1'' }];
$scope.addItem = function (){
i++;
//add the item.
$scope.items.push({ id: i, name: ''Item '' + i});
//now scroll to it.
$location.hash(''item'' + i);
$anchorScroll();
};
});
Y aquí hay un plunk: http://plnkr.co/edit/xi2r8wP6ZhQpmJrBj1jM?p=preview
Y si te interesa una solución de javascript pura, aquí hay una:
Invoque runScroll en su código con el identificador de contenedor primario y el id de desplazamiento de destino:
function runScroll(parentDivId,targetID) {
var longdiv;
longdiv = document.querySelector("#" + parentDivId);
var div3pos = document.getElementById(targetID).offsetTop;
scrollTo(longdiv, div3pos, 600);
}
function scrollTo(element, to, duration) {
if (duration < 0) return;
var difference = to - element.scrollTop;
var perTick = difference / duration * 10;
setTimeout(function () {
element.scrollTop = element.scrollTop + perTick;
if (element.scrollTop == to) return;
scrollTo(element, to, duration - 10);
}, 10);
}
Referencia: JavaScript del navegador cruzado (no jQuery ...) scroll to top animation
Utilicé la respuesta de andrew joslin, que funciona muy bien pero desencadenó un cambio de ruta angular, que creó un desplazamiento de aspecto nervioso para mí. Si quiere evitar disparar un cambio de ruta,
myApp.directive(''scrollOnClick'', function() {
return {
restrict: ''A'',
link: function(scope, $elm, attrs) {
var idToScroll = attrs.href;
$elm.on(''click'', function(event) {
event.preventDefault();
var $target;
if (idToScroll) {
$target = $(idToScroll);
} else {
$target = $elm;
}
$("body").animate({scrollTop: $target.offset().top}, "slow");
return false;
});
}
}
});
respuesta muy clara, usando solo ANGULARJS, no hay ninguna JQUERY depende
en su html en algún lugar en la parte inferior <back-top>some text</back-top>
en su html en algún lugar en la parte superior <div id="top"></div>
en tu js:
/**
* @ngdoc directive
* @name APP.directive:backTop
<pre>
<back-top></back-top>
</pre>
*/
angular
.module(''APP'')
.directive(''backTop'', [''$location'', ''$anchorScroll'' ,function($location, $anchorScroll) {
return {
restrict: ''E'',
replace: true,
transclude: true,
template: ''<span class=/'btn btn-mute pull-right/'><i class=/'glyphicon glyphicon-chevron-up/'></i><ng-transclude></ng-transclude></span>'',
scope: {
},
link: function(scope, element) {
element.on(''click'', function(event) {
$anchorScroll([''top'']);
});
}
};
}]);