web-dev-qa-db-fra.com

Comment mettre à jour window.location.hash sans sauter de document?

J'ai un panneau coulissant installé sur mon site web.

Quand il a fini d'animer, je règle le hachage comme si

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

(Il s'agit d'un rappel et la id est affectée plus tôt).

Cela fonctionne bien, pour permettre à l'utilisateur de marquer le panneau du marque-page et également pour que la version non JavaScript fonctionne.

Cependant, lorsque je mets à jour le hachage, le navigateur accède à 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 hachage de la fenêtre, mais not laisser le navigateur faire défiler jusqu'à l'élément si le hachage existe? Une sorte de event.preventDefault() genre de chose?

J'utilise jQuery 1.4 et le plugin scrollTo .

Merci beaucoup!

Mettre à jour

Voici le code qui modifie 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;

            }
    });
});
141
alex

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

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

Le crédit va à Lea Verou

220
Attila Fulop

Le problème est que vous définissez window.location.hash sur l'attribut ID d'un élément. C'est le comportement attendu du navigateur pour accéder à cet élément, que vous utilisiez ou non "preventDefault ()".

Une façon de contourner ce problème consiste à préfixer le hachage avec une valeur arbitraire comme ceci:

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

Ensuite, tout ce que vous avez à faire est de vérifier le hachage préfixé au chargement de la page. En prime, vous pouvez même faire défiler en douceur, puisque vous êtes maintenant en contrôle de la valeur de hachage ...

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

Si vous avez besoin que cela fonctionne à tout moment (et pas seulement lors du chargement initial de la page), vous pouvez utiliser une fonction pour surveiller les modifications apportées à la valeur de hachage et passer à l'élément approprié à la volée:

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

Solution bon marché et méchante .. Utilisez le # moche! style.

Pour le définir:

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

Pour le lire:

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

Etant donné qu’il ne correspond pas et que l’ancre ou l’id de la page ne correspond pas, il ne sautera pas.

25
Gavin Brock

Pourquoi n'obtenez-vous pas la position de défilement actuelle, mettez-la dans une variable puis assignez le hachage et remettez la page en arrière jusqu'à son emplacement précédent:

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

cela devrait marcher

13
user706270

J'ai utilisé comme combinaison la solution Attila Fulop (Lea Verou) pour les navigateurs modernes et la solution Gavin Brock pour les anciens navigateurs:

if (history.pushState) {
    // IE10, Firefox, Chrome, etc.
    window.history.pushState(null, null, '#' + id);
} else {
    // IE9, IE8, etc
    window.location.hash = '#!' + id;
}

Comme observé par Gavin Brock, pour récupérer l'identifiant, vous devrez traiter la chaîne (qui dans ce cas peut avoir ou non le "!") Comme suit:

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

Avant cela, j'avais essayé une solution similaire à celle proposée par user706270, mais cela ne fonctionnait pas bien avec Internet Explorer: comme son moteur Javascript n'est pas très rapide, vous pouvez remarquer l'augmentation et la diminution du défilement qui produit un effet visuel désagréable.

10
aldemarcalazans

Je ne sais pas si vous pouvez modifier l'élément d'origine, mais que diriez-vous de passer de l'utilisation de l'identifiant attr à autre chose, comme data-id? Ensuite, il suffit de lire la valeur de data-id pour votre valeur de hachage et elle ne sautera pas.

1
Jon B

Cette solution a fonctionné pour moi

// store the currently selected tab in the hash value
    if(history.pushState) {
        window.history.pushState(null, null, '#' + id);
    }
    else {
        window.location.hash = id;
    }

// on load of the page: switch to the currently selected tab
var hash = window.location.hash;
$('#myTab a[href="' + hash + '"]').tab('show');

Et mon code js complet est

$('#myTab a').click(function(e) {
  e.preventDefault();
  $(this).tab('show');
});

// store the currently selected tab in the hash value
$("ul.nav-tabs > li > a").on("shown.bs.tab", function(e) {
  var id = $(e.target).attr("href").substr(1);
    if(history.pushState) {
        window.history.pushState(null, null, '#' + id);
    }
    else {
        window.location.hash = id;
    }
   // window.location.hash = '#!' + id;
});

// on load of the page: switch to the currently selected tab
var hash = window.location.hash;
// console.log(hash);
$('#myTab a[href="' + hash + '"]').tab('show');
0
Rohit Dhiman

Cette solution a fonctionné pour moi. 

Le problème avec le paramètre location.hash est que la page passera à cet identifiant s'il se trouve sur la page.

Le problème avec window.history.pushState est qu’il ajoute une entrée à l’historique pour chaque onglet sur lequel l’utilisateur clique. Ensuite, lorsque l'utilisateur clique sur le bouton back, il passe à l'onglet précédent. (ce peut ou peut ne pas être ce que vous voulez. ce n'était pas ce que je voulais).

Pour moi, replaceState était la meilleure option car il ne remplace que l'historique actuel. Ainsi, lorsque l'utilisateur clique sur le bouton back, il passe à la page précédente.

$('#tab-selector').tabs({
  activate: function(e, ui) {
    window.history.replaceState(null, null, ui.newPanel.selector);
  }
});

Découvrez les Documentation de l'historique de l'API sur MDN.

0
Mike Vallano

Lors de l'utilisation de laravel framework, l'utilisation de la fonction route-> back () posait quelques problèmes, car elle effaçait mon hash. Afin de garder mon hash, j'ai créé une fonction simple:

$(function() {   
    if (localStorage.getItem("hash")    ){
     location.hash = localStorage.getItem("hash");
    }
}); 

et je le mets dans mon autre fonction JS comme ceci:

localStorage.setItem("hash", myvalue);

Vous pouvez nommer vos valeurs de stockage locales comme bon vous semble; le mien nommé hash.

Par conséquent, si le hachage est défini sur PAGE1 et que vous naviguez ensuite vers PAGE2; le hachage sera recréé sur PAGE1 lorsque vous cliquez sur Précédent sur PAGE2.

0
Andrew