top javascript angularjs anchor hashtag

javascript - top - Cómo manejar el enlace de hash de anclaje en AngularJS



ng-href angularjs (27)

¿Alguno de ustedes sabe manejar bien el enlace de hash de ancla en AngularJS ?

Tengo el siguiente marcado para una simple página de preguntas frecuentes

<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>

Al hacer clic en cualquiera de los enlaces anteriores, AngularJS intercepta y me dirige a una página completamente diferente (en mi caso, una página 404 ya que no hay rutas que coincidan con los enlaces).

Mi primer pensamiento fue crear una ruta que coincida con " / faq /: chapter " y en el controlador correspondiente verifique $routeParams.chapter después de un elemento correspondiente y luego use jQuery para desplazarse hacia abajo.

Pero luego AngularJS me caga de nuevo y simplemente se desplaza a la parte superior de la página de todos modos.

Entonces, ¿alguien aquí hizo algo similar en el pasado y conoce una buena solución?

Edición: Cambiar a html5Mode debería resolver mis problemas, pero de todos modos tenemos que admitir IE8 +, así que me temo que no es una solución aceptada: /


Basado en @Stoyan se me ocurrió la siguiente solución:

app.run(function($location, $anchorScroll){ var uri = window.location.href; if(uri.length >= 4){ var parts = uri.split(''#!#''); if(parts.length > 1){ var anchor = parts[parts.length -1]; $location.hash(anchor); $anchorScroll(); } } });



En algún momento de la aplicación hash angularjs, la navegación no funciona y las bibliotecas javascript jquery de bootstrap hacen un uso extensivo de este tipo de navegación, para que funcione agregue target="_self" a la etiqueta de anclaje. por ejemplo, <a data-toggle="tab" href="#id_of_div_to_navigate" target="_self">


En el cambio de ruta, se desplazará a la parte superior de la página.

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

Pon este código en tu controlador.


En mi caso, noté que la lógica de enrutamiento se activaba si modificaba $location.hash() . El siguiente truco funcionó ..

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


En mi mente, @slugslog lo tenía, pero cambiaría una cosa. Yo usaría reemplazar en su lugar para que no tenga que restablecerlo.

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

Búsqueda de Docs para "Reemplazar método"


Estás buscando $anchorScroll() .

$anchorScroll()

Y aquí está la fuente.

Básicamente, simplemente lo inyectas y lo llamas en tu controlador, y te desplazará a cualquier elemento con el ID que se encuentra en $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>

Aquí hay un plunker para demostrar

EDITAR: para usar esto con enrutamiento.

Configure su ruta angular como de costumbre, luego solo agregue el siguiente código.

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

y su enlace se vería así:

<a href="#/test?scrollTo=foo">Test/Foo</a>

Aquí hay un Plunker que muestra el desplazamiento con enrutamiento y $ anchorScroll

Y aún más simple:

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

y su enlace se vería así:

<a href="#/test#foo">Test/Foo</a>


Esta fue mi solución usando una directiva que parece más angular-y porque estamos tratando con el DOM:

Plnkr por aquí

github

CÓDIGO

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>

Utilicé el servicio $ anchorScroll. Para contrarrestar la actualización de la página que acompaña al cambio de hash, continué y cancelé el evento locationChangeStart. Esto me funcionó porque tenía una página de ayuda conectada a un interruptor ng y las actualizaciones romperían la aplicación.


Estaba tratando de hacer que mi aplicación Angular se desplazara a un ancla que se estaba cargando y encontré las reglas de reescritura de URL de $ routeProvider

Después de una larga experimentación me decidí por esto:

  1. registre un controlador de eventos document.onload desde la sección .run () del módulo de la aplicación Angular.
  2. en el controlador, averigüe qué se suponía que tenía la etiqueta de anclaje original realizando algunas operaciones de cadena.
  3. sobrescribir location.hash con la etiqueta de ancla reducida (lo que hace que $ routeProvider la sobrescriba de inmediato con su regla "# /". Pero eso está bien, porque Angular ahora está sincronizado con lo que está sucediendo en la 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(); } } });


Este es un post antiguo, pero pasé mucho tiempo investigando varias soluciones, así que quería compartir una más simple. Solo agregando target="_self" a la etiqueta <a> arreglé para mí El enlace funciona y me lleva a la ubicación correcta en la página.

Sin embargo, Angular aún inyecta algunas rarezas con el # en la URL, por lo que puede tener problemas al usar el botón de retroceso para la navegación y tal después de usar este método.


Este es un tipo de solución sucia al crear una directiva personalizada que se desplazará al elemento especificado (con "preguntas frecuentes")

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


Este puede ser un nuevo atributo para ngView, pero he podido conseguir que los enlaces hash de anclaje funcionen con angular-route utilizando el ngView autoscroll y "doble hashes".

ngView (ver desplazamiento automático)

(El siguiente código fue usado con la correa angular)

<!-- 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>


Estoy usando AngularJS 1.3.15 y parece que no tengo que hacer nada especial.

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

Por lo tanto, lo siguiente funciona para mí en mi HTML:

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

No tuve que hacer ningún cambio en mi controlador o JavaScript en absoluto.


Intente establecer un prefijo hash para rutas angulares $locationProvider.hashPrefix(''!'')

Ejemplo completo:

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


Logré evitar esto en la lógica de ruta para mi aplicación.

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


Mi solución con ng-route fue esta simple directiva:

app.directive(''scrollto'', function ($anchorScroll,$location) { return { link: function (scope, element, attrs) { element.click(function (e) { e.preventDefault(); $location.hash(attrs["scrollto"]); $anchorScroll(); }); } }; })

El html se ve como:

<a href="" scrollTo="yourid">link</a>


Ninguna de las soluciones anteriores funciona para mí, pero solo probé esto y funcionó,

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

Entonces me di cuenta de que debía notificar a la página para comenzar con la página de índice y luego usar el ancla tradicional.


No estoy 100% seguro de si esto funciona todo el tiempo, pero en mi aplicación, esto me da el comportamiento esperado.

Digamos que estás en la página ABOUT y que tienes la siguiente ruta:

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

Ahora, en tu 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>

En conclusión

Incluyendo el nombre de la página antes de que el ancla hiciera el truco por mí. Déjame saber acerca de tus pensamientos.

Abajo

Esto volverá a representar la página y luego se desplazará hasta el ancla.

ACTUALIZAR

Una mejor manera es agregar lo siguiente:

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


No hay necesidad de cambiar ninguna ruta o cualquier otra cosa, solo necesita usar target="_self" al crear los enlaces

Ejemplo:

<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>

Y usa el atributo id en tus elementos html como este:

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

No es necesario utilizar ## como se indica / se menciona en los comentarios ;-)


Obtenga su función de desplazamiento fácilmente. También es compatible con el desplazamiento animado / suave como una característica adicional. Detalles para la biblioteca de Angular Scroll :

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

Bower : bower install --save angular-scroll

npm : npm install --save angular-scroll

Versión reducida - solo 9kb

Desplazamiento suave (desplazamiento animado) - sí

Scry Spy - si

Documentación - excelente

Demostración - http://oblador.github.io/angular-scroll/

Espero que esto ayude.


Puedes intentar usar anchorScroll .

Example

Entonces el controlador sería:

app.controller(''MainCtrl'', function($scope, $location, $anchorScroll, $routeParams) { $scope.scrollTo = function(id) { $location.hash(id); $anchorScroll(); } });

Y la vista:

<a href="" ng-click="scrollTo(''foo'')">Scroll to #foo</a>

... y ningún secreto para la identificación del ancla:

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


Si no te gusta usar ng-click aquí hay una solución alternativa. Utiliza un filter para generar la url correcta en función del estado actual. Mi ejemplo utiliza ui.router .

El beneficio es que el usuario verá a dónde se dirige el enlace.

<a href="{{ ''my-element-id'' | anchor }}">My element</a>

El filtro:

.filter(''anchor'', [''$state'', function($state) { return function(id) { return ''/#'' + $state.current.url + ''#'' + id; }; }])


Si siempre conoce la ruta, simplemente puede agregar el ancla de esta manera:

href="#/route#anchorID

donde route es la ruta angular actual y el anchorID coincide con un <a id="anchorID"> algún lugar de la página


Yo podría hacer esto así

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


$anchorScroll funciona para esto, pero hay una manera mucho mejor de usarlo en versiones más recientes de Angular.

Ahora, $anchorScroll acepta el hash como un argumento opcional, por lo que no tiene que cambiar $location.hash en absoluto. ( $anchorScroll() )

Esta es la mejor solución porque no afecta la ruta en absoluto. No pude hacer funcionar ninguna de las otras soluciones porque estoy usando ngRoute y la ruta se volvería a cargar tan pronto como establezca $location.hash(id) , antes de que $anchorScroll pueda hacer su magia.

Aquí está cómo usarlo ... primero, en la directiva o controlador:

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

y luego en la vista:

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

Además, si necesita tener en cuenta una barra de navegación fija (u otra IU), puede configurar el desplazamiento para $ anchorScroll de esta manera (en la función de ejecución del módulo principal):

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


<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>


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