Comment désactiver le «saut» d'ancre lors du chargement d'une page?

111

Je pense que ce n'est peut-être pas possible, je vais essayer d'expliquer du mieux que je peux. J'ai une page contenant des onglets (jquery powered), contrôlés par ce qui suit:

J'utilise ce code, tel que fourni par un autre utilisateur à partir d'une question précédente.

<script type="text/javascript">
    $(function() {

     $('html, body').animate({scrollTop:0}); // this is my "fix"

        var tabContent = $(".tab_content");
        var tabs = $("#menu li");
        var hash = window.location.hash;
     tabContent.not(hash).hide();
        if(hash=="") {
      $('#tab1').fadeIn();
     }
        tabs.find('[href=' + hash + ']').parent().addClass('active');

        tabs.click(function() {
            $(this).addClass('active').siblings().removeClass('active');
            tabContent.hide();
            var activeTab = $(this).find("a").attr("href");

            $(activeTab).fadeIn();
           return false;
        });

    });
</script>

ce code fonctionne très bien lorsque je visite directement la page "onglets".

cependant, j'ai besoin de créer un lien vers des onglets individuels à partir d'autres pages - pour ce faire, le code obtient window.location.hashalors l'onglet approprié.

la page ne "saute" pas à l'ancre à cause de "return false".

cet événement n'est cependant déclenché que sur un événement de clic. par conséquent, si je visite mes "onglets" depuis n'importe quelle autre page, l'effet "saut" est déclenché. Pour lutter contre cela, je fais défiler automatiquement vers le haut de la page, mais je préférerais que cela ne se produise pas.

y a-t-il un moyen de simuler "return false" lorsque la page se charge, empêchant le "saut" d'ancre de se produire.

J'espère que c'est assez clair.

Merci

Ross
la source

Réponses:

143

Votre solution ne fonctionne pas? Je ne sais pas si j'ai bien compris la question - avez-vous une page de démonstration? Tu pourrais essayer:

if (location.hash) {
  setTimeout(function() {

    window.scrollTo(0, 0);
  }, 1);
}

Edit: testé et fonctionne sous Firefox, IE et Chrome sous Windows.
Edit 2: déplacez-vous à l' setTimeout()intérieur du ifbloc, props @vsync.

dave1010
la source
2
héros! Oui, mon «correctif» fonctionnait, mais la page «défilait» (comme mon code le lui disait), et je préférerais qu'elle ne défile pas. votre code fonctionne parfaitement. Je n'avais pas regardé ScrollTo - la fonction est-elle encore nécessaire? il semble fonctionner correctement avec seulement window.scrollTo (0, 0);
Ross
3
Je l'ai essayé dans Firefox sur une page vide sans le setTimeoutet cela n'a pas toujours fonctionné. Vous n'en avez probablement pas besoin si c'est dans jQuery de $(function() {toute façon. Vous n'en avez pas vraiment besoin location.hash, mais c'est bien de le laisser pour que les navigateurs n'aient rien à faire. Vous rappelle également à quoi sert le scrollTo!
dave1010
2
Aujourd'hui, j'ai eu ce même problème. J'ai en fait dû ajouter le hachage (identique aux noms d'onglets / valeurs href) à mes liens de navigation. J'ai fini par ajouter un suffixe de 1 caractère à mes onglets, puis sous-chaîner les valeurs de 1 caractère (str.slice (0, -1) en les comparant à window.location.hash De cette façon, les hachages sont différents et aucun saut ne se produit .
developer10
1
Le ifdevrait être à l'extérieur, pas à l'intérieur. aussi, le minimum pour l'intervalle est d'environ 10, donc 0 ou 1 est le même..as 10. selon le navigateur.
vsync
2
Cela n'empêche PAS le navigateur de sauter sur le hashtag, vous devez mettre un hashtag vide pour éviter le 'jumpieness', voir ma réponse ici stackoverflow.com/a/29823913/826194
Larzan
43

Voir ma réponse ici: Réponse de Stackoverflow

L'astuce consiste simplement à supprimer le hashtag dès que possible et à stocker sa valeur pour votre propre usage:

Il est important de ne pas mettre cette partie du code dans les fonctions $ () ou $ (window) .load () car il serait trop tard et le navigateur s'est déjà déplacé vers la balise.

// store the hash (DON'T put this code inside the $() function, it has to be executed 
// right away before the browser can start scrolling!
var target = window.location.hash,
    target = target.replace('#', '');

// delete hash so the page won't scroll to it
window.location.hash = "";

// now whenever you are ready do whatever you want
// (in this case I use jQuery to scroll to the tag after the page has loaded)
$(window).on('load', function() {
    if (target) {
        $('html, body').animate({
            scrollTop: $("#" + target).offset().top
        }, 700, 'swing', function () {});
    }
});
Larzan
la source
1
J'avais rencontré un bogue avec FF où j'utilisais overflow-y de hauteur maximale sur un div avec une liste très longue, FFwould défiler vers le bas où le nœud caché serait dans le dom. Cela n'utilisait que les trois premières lignes de code réel (pas les commentaires) et cela corrigeait mon problème avec FireFox.
JQII
12

Il existe d'autres moyens de suivre l'onglet sur lequel vous vous trouvez; peut-être définir un cookie, ou une valeur dans un champ caché, etc.

Je dirais que si vous ne voulez pas que la page saute au chargement, vous feriez mieux d'utiliser l'une de ces autres options plutôt que le hachage, car la principale raison d'utiliser le hachage de préférence à eux est d'autoriser exactement ce que vous veulent bloquer.

Un autre point - la page ne sautera pas si vos liens de hachage ne correspondent pas aux noms des balises dans le document, donc peut-être que si vous souhaitez continuer à utiliser le hachage, vous pouvez manipuler le contenu afin que les balises soient nommées différemment. Si vous utilisez un préfixe cohérent, vous pourrez toujours utiliser Javascript pour passer de l'un à l'autre.

J'espère que cela pourra aider.

Spudley
la source
2
Bons points. N'oubliez pas d'essayer de garder la page utilisable / accessible avec JS / CSS désactivé.
dave1010
12

J'ai utilisé la solution de dave1010, mais c'était un peu nerveux quand je l'ai mise dans la fonction $ (). Ready. Alors j'ai fait ceci: (pas à l'intérieur du $ (). Ready)

    if (location.hash) {               // do the test straight away
        window.scrollTo(0, 0);         // execute it straight away
        setTimeout(function() {
            window.scrollTo(0, 0);     // run it a bit later also for browser compatibility
        }, 1);
    }
de guingois
la source
10
  1. Le navigateur saute à <element id="abc" />s'il y a du hachage http://site.com/#abc dans l'adresse et que l'élément avec id = "abc" est visible. Alors, il vous suffit devez masquer l'élément par défaut: <element id="anchor" style="display: none" />. S'il n'y a pas d'élément visible avec id = hash sur la page, le navigateur ne sautera pas.

  2. Créez un script qui vérifie le hachage dans l'URL, puis trouve et affiche l'élément approprié (qui est masqué par défaut).

  3. Désactivez le comportement par défaut "lien de type hachage" en liant un événement onclick à un lien et spécifiez-le return false;comme résultat de l'événement onclick.

Quand j'ai implémenté des onglets, j'ai écrit quelque chose comme ça:

    <script>
    $(function () {         
        if (location.hash != "") {
            selectPersonalTab(location.hash);
        }
        else {
            selectPersonalTab("#cards");
        }
    });

    function selectPersonalTab(hash) {
        $("#personal li").removeClass("active");
        $("a[href$=" + hash + "]").closest("li").addClass("active");
        $("#personaldata > div").hide();
        location.hash = hash;
        $(hash).show();
    }

    $("#personal li a").click(function (e) {
        var t = e.target;
        if (t.href.indexOf("#") != -1) {
            var hash = t.href.substr(t.href.indexOf("#"));
            selectPersonalTab(hash);
            return false;
        }
    });
</script>
Sergei Smirnov
la source
6

Aucune des réponses ne fonctionne pas assez bien pour moi, je vois la page sauter à l'ancre puis au sommet pour certaines solutions, certaines réponses ne fonctionnent pas du tout, les choses peuvent être modifiées pendant des années. J'espère que ma fonction aidera quelqu'un.

/**
 * Prevent automatic scrolling of page to anchor by browser after loading of page.
 * Do not call this function in $(...) or $(window).on('load', ...),
 * it should be called earlier, as soon as possible.
 */
function preventAnchorScroll() {
    var scrollToTop = function () {
        $(window).scrollTop(0);
    };
    if (window.location.hash) {
        // handler is executed at most once
        $(window).one('scroll', scrollToTop);
    }

    // make sure to release scroll 1 second after document readiness
    // to avoid negative UX
    $(function () {
        setTimeout(
            function () {
                $(window).off('scroll', scrollToTop);
            },
            1000
        );
    });
}
kdmitry
la source
La meilleure solution que j'ai trouvée jusqu'à présent. Et en fait beaucoup vu.
MarkSkayff
Merci pour ça! Aussi la seule solution qui a fonctionné pour moi après des heures de tentatives, mais la meilleure partie de cette solution pour moi est que je n'ai pas à supprimer le hachage.
Chris Vecchio
Cela ne fonctionne pas si le défileur est déjà en haut de la page lors du chargement de la page, il défilera vers le bas comme d'habitude et une fois la page terminée, il saute en haut. Quelqu'un sait-il que c'est le cas?
robgha01
@ robgha01 veuillez vous assurer que la fonction est exécutée le plus tôt possible et n'attend aucun événement, c'est faux:, appelez $(document).ready(function () { preventAnchorScroll(); });simplement la fonction au tout début de votre JavaScript. Je l'ai testé maintenant, fonctionne pour moi dans Chrome, Firefox et Opera.
kdmitry
4

Le CSS sale corrige uniquement pour rester en défilement à chaque fois que l'ancre est utilisée (pas utile si vous voulez toujours utiliser des ancres pour les sauts de défilement, très utile pour les liens profonds):

.elementsWithAnchorIds::before {
   content: "";
   display: block;
   height: 9999px;
   margin-top: -9999px; //higher thin page height
}
un autre toi
la source
tellement intelligent!
duhaime
3

Bien que la réponse acceptée fonctionne bien, j'ai trouvé que parfois, en particulier sur les pages contenant de grandes images, la barre de défilement saute énormément en utilisant

 window.scrollTo(0, 0);

Ce qui peut être assez gênant pour l'utilisateur.

La solution sur laquelle j'ai opté à la fin est en fait assez simple, et consiste à utiliser un identifiant différent sur la cible de celui utilisé dans location.hash

Par exemple:

Voici le lien sur une autre page

<a href="/page/with/tabs#tab2">Some info found in tab2 on tabs page</a>

Donc, bien sûr, s'il y a un élément avec un ID de tab2 sur la page des onglets, la fenêtre y sautera au chargement.

Vous pouvez donc ajouter quelque chose à l'ID pour l'empêcher:

<div id="tab2-noScroll">tab2 content</div>

Et puis vous pouvez ajouter "-noScroll"à location.hashla javascript:

<script type="text/javascript">
    $(function() {

        var tabContent = $(".tab_content");
        var tabs = $("#menu li");
        var hash = window.location.hash;


     tabContent.not(hash + '-noScroll').hide();                           
        if(hash=="") {       //^ here
      $('#tab1-noScroll').fadeIn();
     }
        tabs.find('[href=' + hash + ']').parent().addClass('active');

        tabs.click(function() {
            $(this).addClass('active').siblings().removeClass('active');
            tabContent.hide();
            var activeTab = $(this).find("a").attr("href") + '-noScroll'; 
                                                               //^ and here

            $(activeTab).fadeIn();
           return false;
        });

    });
</script>
Andrew
la source
2

Dans mon cas, en raison de l'utilisation du lien d'ancrage pour le popup CSS, j'ai utilisé cette façon:

Enregistrez simplement la première chose pageYOffset en cliquant, puis définissez ScrollTop sur cela:

$(document).on('click','yourtarget',function(){
        var st=window.pageYOffset;
        $('html, body').animate({
                'scrollTop' : st
            });
});
Métro Polisue
la source
Après avoir essayé les autres solutions, c'est celle qui a fonctionné pour moi, dans mon cas, le site Web avec lequel je travaillais a utilisé le # dans l'url pour charger une section spécifique d'une caisse. Plutôt que de modifier la fonctionnalité de paiement pour le hachage dans l'url, je viens de l'utiliser. Merci
chris c
1

Je pense que j'ai trouvé un moyen pour les onglets d'interface utilisateur sans refaire la fonctionnalité. Jusqu'à présent, je n'ai trouvé aucun problème.

    $( ".tabs" ).tabs();
    $( ".tabs" ).not(".noHash").bind("tabsshow", function(event, ui) { 
        window.location.hash = "tab_"+ui.tab.hash.replace(/#/,"");
        return false;
    });

    var selectedTabHash = window.location.hash.replace(/tab_/,"");
    var index = $( ".tabs li a" ).index($(".tabs li a[href='"+selectedTabHash+"']"));
    $( ".tabs" ).not(".noHash").tabs('select', index);

Le tout dans un événement prêt. Il ajoute «tab_» pour le hachage mais fonctionne à la fois lorsque vous cliquez dessus et que la page est chargée avec le hachage.

JRomero
la source
1

Cela fonctionnera avec bootstrap v3

$(document).ready(function() {
  if ($('.nav-tabs').length) {
    var hash = window.location.hash;
    var hashEl = $('ul.nav a[href="' + hash + '"]');
    hash && hashEl.tab('show');

    $('.nav-tabs a').click(function(e) {
      e.preventDefault();
      $(this).tab('show');
      window.location.hash = this.hash;
    });

    // Change tab on hashchange
    window.addEventListener('hashchange', function() {
      var changedHash = window.location.hash;
      changedHash && $('ul.nav a[href="' + changedHash + '"]').tab('show');
    }, false);
  }
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>
<div class="container">
<ul class="nav nav-tabs">
  <li class="active"><a data-toggle="tab" href="#home">Home</a></li>
  <li><a data-toggle="tab" href="#menu1">Menu 1</a></li>
</ul>

<div class="tab-content">
  <div id="home" class="tab-pane fade in active">
    <h3>HOME</h3>
    <p>Some content.</p>
  </div>
  <div id="menu1" class="tab-pane fade">
    <h3>Menu 1</h3>
    <p>Some content in menu 1.</p>
  </div>
</div>
</div>

Lasithds
la source
0

Une autre approche

Essayez de vérifier si la page a été défilée, puis réinitialisez la position:

var scrolled = false;

$(window).scroll(function(){
  scrolled = true;
});

if ( window.location.hash && scrolled ) {
  $(window).scrollTop( 0 );
}

Heres a demo

hitautodestruct
la source
ne fonctionne pas bro ... la charge initiale est en bas ... après l'actualisation, elle reste en haut
Martin Zvarík
0

Je n'ai pas eu beaucoup de succès avec les setTimeoutméthodes ci-dessus dans Firefox.

Au lieu d'un setTimeout, j'ai utilisé une fonction onload:

window.onload = function () {
    if (location.hash) {
        window.scrollTo(0, 0);
    }
};

C'est encore très glitch, malheureusement.

bozdoz
la source
car onload s'exécute une fois que tout est complètement chargé, y compris les photos ... alors bien sûr, c'est un problème comme ça
Martin Zvarík
0

Je n'ai pas eu de succès constant avec ces solutions.

Apparemment en raison du fait que le saut se produit avant Javascript => référence ( http://forum.jquery.com/topic/preventing-anchor-jump )

Ma solution est de positionner toutes les ancres en haut par défaut avec CSS.

.scroll-target{position:fixed;top:0;left:0;}

Ensuite, utilisez jquery pour faire défiler jusqu'au parent de l'ancre cible, ou un frère (peut-être une balise em vide)

<a class="scroll-target" name="section3"></a><em>&nbsp</em>

jquery exemple pour faire défiler lorsque l'URL est saisie avec hachage
(la page ne doit pas être déjà chargée dans la fenêtre / l'onglet, cela couvre les liens provenant d'autres sources / sources externes)

setTimeout(function() {
    if (window.location.hash) {               
        var hash = window.location.hash.substr(1);   
        var scrollPos = $('.scroll-target[name="'+hash+'"]').siblings('em').offset().top; 
        $("html, body").animate({ scrollTop: scrollPos }, 1000);    
    }
}, 1);

Vous voudrez également empêcher la valeur par défaut des clics d'ancrage sur la page, puis faire défiler jusqu'à leurs cibles

<a class="scroll-to" href="#section3">section three</a>

et jquery

$('a.scroll-to').click(function(){
    var target = $(this).attr('href').substr(1);
    var scrollPos = $('.scroll-target[name="'+target+'"]').siblings('em').offset().top; 
    $("html, body").animate({ scrollTop: scrollPos }, 1000);
    return false;
});

La bonne chose à propos de cette méthode est que les cibles de balises d'ancrage restent structurellement à côté du contenu pertinent, bien que leur position CSS soit en haut.

Cela devrait signifier que les robots des moteurs de recherche n'auront pas de problème.

Cheers, j'espère que cela aide
Gray

grayskale.com
la source
0

Essayez ceci pour empêcher le client de tout type de défilement vertical sur le hachage (dans votre gestionnaire d'événements):

var sct = document.body.scrollTop;
document.location.hash = '#next'; // or other manipulation
document.body.scrollTop = sct;

(rafraîchissement du navigateur)

Andy
la source
0

Résolu mon promlem en faisant ceci:

// navbar height 
var navHeigth = $('nav.navbar').height();    

// Scroll to anchor function
var scrollToAnchor = function(hash) {
  // If got a hash
  if (hash) {
    // Scroll to the top (prevention for Chrome)
    window.scrollTo(0, 0);
    // Anchor element
    var term = $(hash);

    // If element with hash id is defined
    if (term) {

      // Get top offset, including header height
      var scrollto = term.offset().top - navHeigth;

      // Capture id value
      var id = term.attr('id');
      // Capture name value
      var name = term.attr('name');

      // Remove attributes for FF scroll prevention
      term.removeAttr('id').removeAttr('name');
      // Scroll to element
      $('html, body').animate({scrollTop:scrollto}, 0);

      // Returning id and name after .5sec for the next scroll
      setTimeout(function() {
        term.attr('id', id).attr('name', name);
      }, 500);
    }
  }
};

// if we are opening the page by url
if (location.hash) {
  scrollToAnchor(location.hash);
}

// preventing default click on links with an anchor
$('a[href*="#"]').click(function(e) {
  e.preventDefault();
  // hash value
  var hash = this.href.substr(this.href.indexOf("#"));
  scrollToAnchor(hash);
});`
xottabych007
la source