Wie deaktiviere ich den Ankersprung beim Laden einer Seite?

110

Ich denke, das ist möglicherweise nicht möglich, werde versuchen, es so gut wie möglich zu erklären. Ich habe eine Seite mit Registerkarten (jquery powered), die wie folgt gesteuert werden:

Ich verwende diesen Code, wie er von einem anderen Benutzer aus einer vorherigen Frage bereitgestellt wurde.

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

Dieser Code funktioniert hervorragend, wenn ich die Seite "Registerkarten" direkt besuche.

Ich muss jedoch auf einzelne Registerkarten von anderen Seiten verlinken. Dazu erhält der Code window.location.hashdie entsprechende Registerkarte.

Die Seite "springt" nicht zum Anker, weil "return false".

Dieses Ereignis wird jedoch nur bei einem Klickereignis ausgelöst. Wenn ich meine "Tabs" von einer anderen Seite aus besuche, wird der "Sprung" -Effekt ausgelöst. Um dem entgegenzuwirken, scrolle ich automatisch zum Anfang der Seite, aber ich möchte lieber, dass dies nicht passiert.

Gibt es eine Möglichkeit, "return false" beim Laden der Seite zu simulieren, um zu verhindern, dass der "Sprung" des Ankers auftritt?

hoffe das ist klar genug.

Vielen Dank

Ross
quelle

Antworten:

143

Funktioniert Ihr Fix nicht? Ich bin mir nicht sicher, ob ich die Frage richtig verstehe - haben Sie eine Demoseite? Du könntest es versuchen:

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

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

Bearbeiten: getestet und funktioniert in Firefox, IE & Chrome unter Windows.
Bearbeiten 2: Bewegen Sie sich setTimeout()innerhalb des ifBlocks, Requisiten @vsync.

dave1010
quelle
2
Held! Ja, mein "Fix" hat funktioniert, aber die Seite würde "scrollen" (wie mein Code es vorschrieb), und ich würde es vorziehen, wenn sie nicht scrollen würde. Ihr Code funktioniert perfekt. Ich hatte mir ScrollTo nicht angesehen - ist die Funktion überhaupt notwendig? es scheint nur mit window.scrollTo (0, 0) gut zu funktionieren;
Ross
3
Ich habe es in Firefox auf einer leeren Seite ohne das versucht setTimeoutund es hat nicht immer funktioniert. Sie brauchen es wahrscheinlich nicht, wenn es $(function() {sowieso in jQuery ist. Sie brauchen das nicht wirklich location.hash, aber es ist schön, es zu belassen, damit Browser möglicherweise nichts tun müssen. Erinnert Sie auch daran, wofür das scrollTo ist!
Dave1010
2
Heute hatte ich das gleiche Problem. Ich musste tatsächlich den Hash (identisch mit Tab-Namen / href-Werten) zu meinen Navigationslinks hinzufügen. Am Ende habe ich meinen Registerkarten ein 1-Zeichen-Suffix hinzugefügt und dann die Werte beim Vergleich mit window.location.hash mit 1 Zeichen (str.slice (0, -1)) versehen. Auf diese Weise unterscheiden sich die Hashes und es treten keine Sprünge auf .
Entwickler10
1
Das ifsollte draußen sein, nicht drinnen. Außerdem beträgt das Minimum für das Intervall ungefähr 10, sodass 0 oder 1 gleich sind. Wie 10. je nach Browser.
vsync
2
Dies verhindert NICHT, dass der Browser zum Hashtag springt. Sie müssen ein leeres Hashtag einfügen, um die "Sprungkraft" zu verhindern. Siehe meine Antwort hier stackoverflow.com/a/29823913/826194
Larzan
43

Siehe meine Antwort hier: Stackoverflow-Antwort

Der Trick besteht darin, das Hashtag so schnell wie möglich zu entfernen und seinen Wert für den eigenen Gebrauch zu speichern:

Es ist wichtig, dass Sie diesen Teil des Codes nicht in die Funktionen $ () oder $ (Fenster) .load () einfügen, da dies zu spät wäre und der Browser bereits zum Tag gewechselt ist.

// 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
quelle
1
Ich war auf einen Fehler mit FF gestoßen, bei dem ich einen Überlauf mit maximaler Höhe für ein Div mit einer wirklich langen Liste verwendete. FF würde nach unten scrollen, wo sich der versteckte Knoten im Dom befinden würde. Dies verwendete nur die obersten drei Zeilen des tatsächlichen Codes (nicht die Kommentare) und dies korrigierte mein Problem mit FireFox.
JQII
12

Es gibt andere Möglichkeiten, um zu verfolgen, auf welcher Registerkarte Sie sich befinden. Setzen Sie möglicherweise ein Cookie oder einen Wert in ein verstecktes Feld usw. usw.

Ich würde sagen, wenn Sie nicht möchten, dass die Seite beim Laden springt, ist es besser, eine dieser anderen Optionen als den Hash zu verwenden, da der Hauptgrund für die Verwendung des Hash gegenüber diesen darin besteht, genau das zuzulassen, was Sie möchten wollen blockieren.

Ein weiterer Punkt: Die Seite springt nicht, wenn Ihre Hash-Links nicht mit den Namen der Tags im Dokument übereinstimmen. Wenn Sie den Hash also weiterhin verwenden möchten, können Sie den Inhalt so bearbeiten, dass die Tags unterschiedlich benannt werden. Wenn Sie ein konsistentes Präfix verwenden, können Sie weiterhin Javascript verwenden, um zwischen diesen zu wechseln.

Hoffentlich hilft das.

Spudley
quelle
2
Gute Argumente. Vergessen Sie nicht, die Seite bei deaktiviertem JS / CSS nutzbar zu machen.
Dave1010
12

Ich habe die Lösung von dave1010 verwendet, aber es war etwas nervös, als ich sie in die Funktion $ (). Ready einfügte. Also habe ich folgendes gemacht: (nicht innerhalb des $ (). Fertig)

    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);
    }
schief
quelle
10
  1. Der Browser springt zu, <element id="abc" />wenn die Adresse einen http://site.com/#abc-Hash enthält und das Element mit id = "abc" sichtbar ist. Sie sollten das Element also standardmäßig ausblenden : <element id="anchor" style="display: none" />. Wenn auf der Seite kein sichtbares Element mit id = Hash vorhanden ist, würde der Browser nicht springen.

  2. Erstellen Sie ein Skript, das den Hash in der URL überprüft und dann das prrpopriate-Element findet und anzeigt (das standardmäßig ausgeblendet ist).

  3. Deaktivieren Sie das Standardverhalten "Hash-ähnlicher Link", indem Sie ein Onclick-Ereignis an einen Link binden und return false;als Ergebnis eines Onclick-Ereignisses angeben .

Als ich Tabs implementiert habe, habe ich so etwas geschrieben:

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

Keine der Antworten funktioniert für mich nicht gut genug. Ich sehe, wie die Seite vor Anker springt und dann nach oben geht, um einige Lösungen zu finden. Einige Antworten funktionieren überhaupt nicht. Möglicherweise haben sich die Dinge jahrelang geändert. Hoffe, meine Funktion wird jemandem helfen.

/**
 * 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
quelle
Die beste Lösung, die ich bisher gefunden habe. Und tatsächlich viel gesehen.
MarkSkayff
Danke dafür! Auch nur die Lösung, die nach stundenlangen Versuchen für mich funktioniert hat, aber das Beste an dieser Lösung für mich ist, dass ich den Hash nicht entfernen muss.
Chris Vecchio
Dies funktioniert nicht, wenn sich der Scroller beim Laden der Seite bereits oben auf der Seite befindet. Dann wird er wie gewohnt nach unten scrollen und nach Abschluss der Seite nach oben springen. Weiß jemand, wie das der Fall ist?
robgha01
@ robgha01 Bitte stellen Sie sicher, dass die Funktion so schnell wie möglich ausgeführt wird und nicht auf ein Ereignis wartet. Dies ist falsch: $(document).ready(function () { preventAnchorScroll(); });Rufen Sie einfach die Funktion ganz am Anfang Ihres JavaScript auf. Ich habe es jetzt getestet und funktioniert für mich in Chrome, Firefox und Opera.
kdmitry
4

Dirty CSS behebt nur, dass jedes Mal, wenn der Anker verwendet wird, nach oben gescrollt wird (nicht nützlich, wenn Sie weiterhin Anker für Scroll-Sprünge verwenden möchten, sehr nützlich zum Deeplinking):

.elementsWithAnchorIds::before {
   content: "";
   display: block;
   height: 9999px;
   margin-top: -9999px; //higher thin page height
}
andernfalls
quelle
soooooo schlau!
Duhaime
3

Obwohl die akzeptierte Antwort gut funktioniert, habe ich manchmal festgestellt, dass die Bildlaufleiste, insbesondere auf Seiten mit großen Bildern, wild herumspringt

 window.scrollTo(0, 0);

Was für den Benutzer ziemlich ablenkend sein kann.

Die Lösung, für die ich mich am Ende entschieden habe, ist eigentlich ziemlich einfach. Dabei wird auf dem Ziel eine andere ID verwendet als in location.hash

Z.B:

Hier ist der Link auf einer anderen Seite

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

Also natürlich, wenn es ein Element mit der ID von gibt tab2 auf der Registerkarte springt das Fenster beim Laden .

Sie können also etwas an die ID anhängen, um dies zu verhindern:

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

Und dann können Sie hängen Sie "-noScroll"an location.hashder 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
quelle
2

In meinem Fall habe ich wegen der Verwendung des Ankerlinks für das CSS-Popup Folgendes verwendet:

Speichern Sie einfach die Seite YOffset als erstes beim Klicken und setzen Sie dann das ScrollTop auf Folgendes:

$(document).on('click','yourtarget',function(){
        var st=window.pageYOffset;
        $('html, body').animate({
                'scrollTop' : st
            });
});
Metro Polisue
quelle
Nachdem ich die anderen Lösungen ausprobiert hatte, funktionierte diese für mich. In meinem Fall verwendete die Website, mit der ich arbeitete, das # in der URL, um einen bestimmten Abschnitt einer Kasse zu laden. Anstatt die Checkout-Funktionalität für den Hash in der URL zu ändern, habe ich dies gerade verwendet. Danke
Chris C
1

Ich glaube, ich habe einen Weg für UI-Registerkarten gefunden, ohne die Funktionalität zu wiederholen. Bisher habe ich keine Probleme gefunden.

    $( ".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);

Alles innerhalb einer fertigen Veranstaltung. Es stellt "tab_" für den Hash voran, funktioniert jedoch sowohl beim Klicken als auch beim Laden der Seite mit dem Hash.

JRomero
quelle
1

Dies funktioniert mit 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
quelle
0

Ein anderer Ansatz

Überprüfen Sie, ob die Seite gescrollt wurde, und setzen Sie erst dann die Position zurück:

var scrolled = false;

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

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

Heres a demo

hitautodestruct
quelle
funktioniert nicht, Bruder ... die anfängliche Ladung ist unten ... nach der Aktualisierung bleibt sie oben
Martin Zvarík
0

Ich hatte mit dem oben genannten nicht viel Erfolg setTimeout Methoden in Firefox .

Anstelle eines setTimeout habe ich eine Onload-Funktion verwendet:

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

Es ist leider immer noch sehr unangenehm.

bozdoz
quelle
weil onload läuft, nachdem alles vollständig geladen ist, einschließlich Fotos ... also ist es natürlich auf diese Weise
fehlerhaft
0

Ich habe mit diesen Lösungen keinen konsequenten Erfolg gehabt.

Anscheinend aufgrund der Tatsache, dass der Sprung vor Javascript => Referenz erfolgt ( http://forum.jquery.com/topic/preventing-anchor-jump )

Meine Lösung besteht darin, alle Anker mit CSS standardmäßig oben zu positionieren.

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

Verwenden Sie dann jquery, um zum übergeordneten Element des Zielankers oder zu einem Geschwister (möglicherweise einem leeren em-Tag) zu scrollen.

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

jQuery-Beispiel für das Scrollen, wenn eine URL mit Hash eingegeben wird
(Seite darf nicht bereits in Fenster / Tab geladen sein, dies deckt Links von anderen / externen Quellen ab)

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

Außerdem möchten Sie die Standardeinstellung für Ankerklicks auf der Seite verhindern und dann zu ihren Zielen scrollen

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

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

Das Gute an dieser Methode ist, dass die Ankertag-Ziele strukturell neben dem relevanten Inhalt bleiben, obwohl ihre CSS-Position oben liegt.

Dies sollte bedeuten, dass Suchmaschinen-Crawler kein Problem haben.

Prost, ich hoffe das hilft
Gray

grayskale.com
quelle
0

Versuchen Sie dies, um zu verhindern, dass der Client beim Hash-Ändern (in Ihrem Event-Handler) vertikal scrollt:

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

(Browser neu zeichnen)

Andy
quelle
0

Mein Problem wurde dadurch gelöst:

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