181 votes

Comment puis-je mettre à jour window.location.hash sans sauter le document?

J'ai mis en place un panneau coulissant sur mon site web.

Une fois l'animation terminée, j'ai défini le hash de la manière suivante :

function() {
   window.location.hash = id;
}

(c'est un rappel, et l'id est attribué auparavant).

Cela fonctionne bien, permettant à l'utilisateur de mettre en signet le panneau, et aussi pour que la version sans JavaScript fonctionne.

Cependant, lorsque je mets à jour le hash, le navigateur se déplace vers l'emplacement. Je suppose que c'est le comportement attendu.

Ma question est : comment puis-je empêcher cela ? C'est-à-dire, comment puis-je changer le hash de la fenêtre, mais ne pas faire défiler le navigateur jusqu'à l'élément si le hash existe ? Une sorte de event.preventDefault() quelque chose comme ça ?

J'utilise jQuery 1.4 et le plugin scrollTo.

Merci beaucoup !

Mise à jour

Voici le code qui change le panneau.

$('#something a').click(function(event) {
    event.preventDefault();
    var link = $(this);
    var id = link[0].hash;

    $('#slider').scrollTo(id, 800, {
        onAfter: function() {

            link.parents('li').siblings().removeClass('active');
            link.parent().addClass('active');
            window.location.hash = id;

            }
    });
});

2 votes

Je suppose que vous avez essayé event.preventDefault() :)

0 votes

@Marko Je ne sais pas où le placer!

0 votes

Pouvez-vous poster le reste de votre code ?

291voto

Attila Fulop Points 748

Il existe une solution de contournement en utilisant l'API d'historique sur les navigateurs modernes avec un fallback sur les anciens :

if(history.pushState) {
    history.pushState(null, null, '#myhash');
}
else {
    location.hash = '#myhash';
}

Le crédit revient à Lea Verou

0 votes

C'est la meilleure réponse, à mon avis.

11 votes

Notez que pushState a pour effet secondaire d'ajouter un état à la pile d'historique du navigateur. En d'autres termes, lorsque l'utilisateur clique sur le bouton de retour, rien ne se produira à moins que vous n'ajoutiez également un écouteur d'événements popstate.

41 votes

@DavidCook - Nous pourrions également utiliser history.replaceState (ce qui, pour les changements de hachage, pourrait être plus logique) pour éviter le besoin d'un écouteur d'événement popstate.

54voto

Derek Hunziker Points 6663

Le problème est que vous définissez window.location.hash sur l'attribut ID d'un élément. Il est attendu que le navigateur se déplace jusqu'à cet élément, que vous utilisiez "preventDefault()" ou non.

Une façon de contourner cela est de préfixer le hash avec une valeur arbitraire comme ceci :

window.location.hash = 'panel-' + id.replace('#', '');

Ensuite, il vous suffit de vérifier le hash préfixé au chargement de la page. En prime, vous pouvez même faire défiler en douceur jusqu'à lui puisque vous contrôlez maintenant la valeur du hash...

$(function(){
    var h = window.location.hash.replace('panel-', '');
    if (h) {
        $('#slider').scrollTo(h, 800);
    }
});

Si vous avez besoin que cela fonctionne en tout temps (et pas seulement lors du chargement initial de la page), vous pouvez utiliser une fonction pour surveiller les changements de la valeur du hash et vous déplacer vers l'élément correct en temps réel :

var foundHash;
setInterval(function() {
    var h = window.location.hash.replace('panel-', '');
    if (h && h !== foundHash) {
        $('#slider').scrollTo(h, 800);
        foundHash = h;
    }
}, 100);

3 votes

C'est la seule solution qui répond réellement à la question - permettant le hachage sans saut.

0 votes

Cela répond vraiment à la question en expliquant l'ajout et la suppression de la valeur arbitraire pour le hachage afin d'éviter le saut selon le comportement par défaut du navigateur.

1 votes

Bonne solution, mais affaiblit la solution du l'OP car cela annule l'utilisation de la fonction de signets

30voto

Gavin Brock Points 3296

Solution bon marché et médiocre.. Utilisez le style laid #!.

Pour le définir :

window.location.hash = '#!' + id;

Pour le lire :

id = window.location.hash.replace(/^#!/, '');

Puisque cela ne correspond ni à une ancre ni à un id sur la page, cela ne fera pas de saut.

4 votes

J'ai dû préserver la compatibilité avec IE 7 et certaines versions mobiles du site. Cette solution était la plus propre pour moi. En général, je choisirais les solutions pushState.

1 votes

En définissant le hash avec: window.location.hash = '#/' + id; puis en le remplaçant par: window.location.hash.replace(/^#\//, '#'); rendra l'URL un peu plus jolie -> projects/#/tab1

13voto

user706270 Points 43

Pourquoi ne pas obtenir la position de défilement actuelle, la mettre dans une variable puis attribuer le hachage et remettre le défilement de la page à l'endroit où il se trouvait :

var yScroll=document.body.scrollTop;
window.location.hash = id;
document.body.scrollTop=yScroll;

cela devrait fonctionner

2 votes

Hm, cela fonctionnait pour moi pendant un certain temps, mais il semble que cela ne fonctionne plus sur Firefox depuis quelques mois...

1voto

freaksauce Points 11

Je ne suis pas sûr si vous pouvez modifier l'élément d'origine mais que diriez-vous de passer de l'utilisation de l'attribut id à quelque chose d'autre comme data-id? Ensuite, il suffit de lire la valeur de data-id pour votre valeur de hachage et cela ne sautera pas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X