Bagaimana cara menonaktifkan anchor "jump" saat memuat halaman?

111

Saya pikir ini mungkin tidak mungkin, akan mencoba dan menjelaskan sebaik mungkin. Saya memiliki halaman yang berisi tab (bertenaga jquery), dikontrol oleh yang berikut:

Saya menggunakan kode ini, seperti yang diberikan oleh pengguna lain dari pertanyaan sebelumnya.

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

kode ini berfungsi dengan baik saat saya mengunjungi halaman "tab" secara langsung.

namun, saya perlu menautkan ke tab individual dari halaman lain - jadi untuk melakukan ini, kode mendapatkan window.location.hashlalu menampilkan tab yang sesuai.

halaman tidak "melompat" ke jangkar karena "return false".

Namun, peristiwa ini hanya dipicu pada peristiwa klik. karenanya, jika saya mengunjungi "tab" saya dari halaman lain, efek "lompat" dipicu. Untuk mengatasi ini, saya secara otomatis menggulir ke bagian atas halaman, tetapi saya lebih suka ini tidak terjadi.

apakah ada cara untuk mensimulasikan "return false" saat halaman dimuat, mencegah jangkar "melompat" terjadi.

harap ini cukup jelas.

Terima kasih

Ross
sumber

Jawaban:

143

Apakah perbaikan Anda tidak berhasil? Saya tidak yakin apakah saya memahami pertanyaan dengan benar - apakah Anda memiliki halaman demo? Kamu bisa mencoba:

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

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

Edit: diuji dan berfungsi di Firefox, IE & Chrome di Windows.
Edit 2: pindah ke setTimeout()dalam ifblok, props @vsync.

dave1010
sumber
2
pahlawan! Ya, "perbaikan" saya berhasil, tetapi halaman akan "bergulir" (seperti yang diperintahkan kode saya), dan saya lebih suka halaman itu tidak bergulir. kode Anda berfungsi dengan sempurna. Saya belum melihat ScrollTo - apakah fungsinya perlu? tampaknya berfungsi dengan baik hanya dengan window.scrollTo (0, 0);
Ross
3
Saya mencobanya di Firefox pada halaman kosong tanpa setTimeoutdan tidak selalu berhasil. Anda mungkin tidak membutuhkannya jika ada di jQuery $(function() {. Anda tidak benar-benar membutuhkannya location.hash, tapi senang membiarkannya begitu browser mungkin tidak perlu melakukan apapun. Juga mengingatkan Anda untuk apa scrollTo itu!
dave1010
2
Hari ini saya mengalami masalah yang sama. Saya sebenarnya harus menambahkan hash (identik dengan nama tab / nilai href) ke link nav saya. Saya akhirnya menambahkan sufiks 1-char ke tab saya, dan kemudian mensubstring nilainya dengan 1 char (str.slice (0, -1) saat membandingkannya dengan window.location.hash Dengan cara ini hash berbeda dan tidak ada lompatan yang terjadi .
pengembang10
1
The ifharus di luar, tidak di dalam. juga, interval minimum adalah sekitar 10, jadi 0 atau 1 sama .. sebagai 10. tergantung pada browser.
vsync
2
Ini TIDAK mencegah browser untuk melompat ke hashtag, Anda harus meletakkan hashtag kosong untuk mencegah 'kegelisahan', lihat jawaban saya di sini stackoverflow.com/a/29823913/826194
Larzan
43

Lihat jawaban saya di sini: Jawaban Stackoverflow

Triknya adalah dengan segera menghapus hashtag ASAP dan menyimpan nilainya untuk Anda gunakan sendiri:

Penting bagi Anda untuk tidak meletakkan bagian kode itu dalam fungsi $ () atau $ (window) .load () karena akan terlambat dan browser sudah pindah ke tag.

// 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
sumber
1
Saya telah mengalami bug dengan FF di mana saya menggunakan max-height overflow-y pada div dengan daftar yang sangat panjang, FF akan menggulir ke bawah di mana node tersembunyi akan berada di dom. Ini hanya menggunakan tiga baris teratas dari kode sebenarnya (bukan komentar) dan ini memperbaiki masalah saya dengan FireFox.
JQII
12

Ada cara lain untuk melacak tab yang Anda buka; mungkin menyetel cookie, atau nilai di bidang tersembunyi, dll.

Saya akan mengatakan bahwa jika Anda tidak ingin halaman melompat saat dimuat, Anda akan lebih baik menggunakan salah satu dari opsi lain ini daripada hash, karena alasan utama menggunakan hash dalam preferensi untuk mereka adalah untuk mengizinkan apa yang Anda inginkan. ingin memblokir.

Hal lain - halaman tidak akan melompat jika tautan hash Anda tidak cocok dengan nama tag di dokumen, jadi mungkin jika Anda ingin tetap menggunakan hash, Anda dapat memanipulasi konten sehingga tag diberi nama berbeda. Jika Anda menggunakan awalan yang konsisten, Anda masih dapat menggunakan Javascript untuk beralih di antaranya.

Semoga membantu.

Spudley
sumber
2
Poin bagus. Jangan lupa untuk mencoba menjaga halaman yang dapat digunakan / dapat diakses dengan JS / CSS dimatikan.
dave1010
12

Saya menggunakan solusi dave1010, tetapi agak gelisah ketika saya memasukkannya ke dalam fungsi siap $ (). Jadi saya melakukan ini: (bukan di dalam $ (). 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);
    }
miring
sumber
10
  1. Browser melompat ke <element id="abc" />jika ada hash http://site.com/#abc di alamat dan elemen dengan id = "abc" terlihat. Jadi, Anda hanya harus menyembunyikan elemen secara default: <element id="anchor" style="display: none" />. Jika tidak ada elemen yang terlihat dengan id = hash di halaman, browser tidak akan melompat.

  2. Buat skrip yang memeriksa hash di url, lalu temukan dan tampilkan elemen prrpopriate (yang disembunyikan secara default).

  3. Nonaktifkan perilaku default "tautan seperti hash" dengan mengikat kejadian onclick ke tautan dan tentukan return false;sebagai hasil dari kejadian onclick.

Ketika saya menerapkan tab, saya menulis sesuatu seperti itu:

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

Tidak ada jawaban yang tidak bekerja cukup baik untuk saya, saya melihat halaman melompat ke jangkar dan kemudian ke atas untuk beberapa solusi, beberapa jawaban tidak berfungsi sama sekali, mungkin ada hal yang berubah selama bertahun-tahun. Semoga fungsi saya akan membantu seseorang.

/**
 * 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
sumber
Solusi terbaik yang saya temukan sejauh ini. Dan benar-benar melihat banyak hal.
MarkSkayff
Terima kasih untuk ini! Juga hanya solusi yang berhasil untuk saya setelah berjam-jam mencoba, tetapi bagian terbaik dari solusi ini bagi saya adalah saya tidak perlu menghapus hash.
Chris Vecchio
Ini tidak berfungsi jika penggulung sudah berada di bagian atas halaman pada pemuatan halaman maka itu akan menggulir ke bawah seperti biasa dan setelah halaman selesai itu melompat ke atas. Adakah yang tahu bagaimana ini terjadi?
robgha01
@ robgha01 pastikan bahwa fungsi dijalankan secepat mungkin dan tidak menunggu kejadian apapun, ini salah:, $(document).ready(function () { preventAnchorScroll(); });panggil saja fungsi tersebut di awal JavaScript Anda. Saya mengujinya sekarang, berfungsi untuk saya di Chrome, Firefox, dan Opera.
kdmitry
4

CSS kotor hanya memperbaiki untuk tetap menggulir ke atas setiap kali jangkar digunakan (tidak berguna jika Anda masih ingin menggunakan jangkar untuk gulir-lompat, sangat berguna untuk tautan dalam):

.elementsWithAnchorIds::before {
   content: "";
   display: block;
   height: 9999px;
   margin-top: -9999px; //higher thin page height
}
kamu yang lain
sumber
sangaaaat pintar!
duhaime
3

Meskipun jawaban yang diterima berfungsi dengan baik, saya menemukan bahwa kadang-kadang, terutama pada halaman yang berisi gambar besar yang bilah gulir akan melompat dengan liar menggunakan

 window.scrollTo(0, 0);

Yang bisa sangat mengganggu pengguna.

Solusi yang saya tetapkan pada akhirnya sebenarnya cukup sederhana, dan itu menggunakan ID yang berbeda pada target dengan yang digunakan di location.hash

Misalnya:

Ini adalah tautan di beberapa halaman lain

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

Jadi tentu saja jika ada elemen dengan ID tab2pada halaman tab jendela akan melompat ke sana saat dimuat.

Jadi, Anda dapat menambahkan sesuatu ke ID untuk mencegahnya:

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

Dan kemudian Anda dapat menambahkan "-noScroll"ke location.hashdalam 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
sumber
2

Dalam kasus saya karena menggunakan tautan jangkar untuk sembulan CSS, saya telah menggunakan cara ini:

Simpan saja pageYOffset hal pertama saat klik dan kemudian atur ScrollTop ke sana:

$(document).on('click','yourtarget',function(){
        var st=window.pageYOffset;
        $('html, body').animate({
                'scrollTop' : st
            });
});
Metro Polisue
sumber
Setelah mencoba solusi lain, inilah yang berhasil untuk saya, dalam kasus saya, situs web tempat saya bekerja menggunakan # di url untuk memuat bagian tertentu dari pembayaran. Daripada memodifikasi fungsionalitas checkout untuk hash di url, saya baru saja menggunakan ini. Terima kasih
chris c
1

Saya rasa saya telah menemukan cara untuk Tab UI tanpa mengulangi fungsinya. Sejauh ini saya belum menemukan masalah.

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

Semua dalam acara yang siap. Ini menambahkan "tab_" untuk hash tetapi berfungsi baik saat diklik dan halaman dimuat dengan hash.

JRomero
sumber
1

Ini akan bekerja dengan 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
sumber
0

Pendekatan lain

Coba periksa apakah halaman telah digulir dan baru kemudian atur ulang posisi:

var scrolled = false;

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

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

Heres a demo

hitautodestruct
sumber
tidak berfungsi bro ... muatan awal ada di bawah ... setelah penyegaran tetap di atas
Martin Zvarík
0

Saya tidak terlalu berhasil dengan setTimeoutmetode di atas di Firefox.

Alih-alih setTimeout, saya telah menggunakan fungsi onload:

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

Sayangnya masih sangat glitchy.

bozdoz.dll
sumber
karena onload berjalan setelah semuanya terisi penuh, termasuk foto ... jadi tentu saja ini
bermasalah
0

Saya belum berhasil secara konsisten dengan solusi ini.

Rupanya karena fakta bahwa lompatan terjadi sebelum Javascript => referensi ( http://forum.jquery.com/topic/preventing-anchor-jump )

Solusi saya adalah memposisikan semua jangkar di atas secara default dengan CSS.

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

Kemudian gunakan jquery untuk menggulir ke induk dari jangkar target, atau saudara kandung (mungkin tag em kosong)

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

Contoh jquery untuk scrolling ketika URL dimasukkan dengan hash
(halaman tidak boleh dimuat di window / tab, ini mencakup link dari sumber lain / luar)

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

Anda juga ingin mencegah default untuk klik jangkar saat berada di halaman dan kemudian menggulir ke targetnya

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

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

Hal yang baik tentang metode ini adalah target tag anchor, tetap secara struktural di samping konten yang relevan, meskipun posisi CSS mereka ada di atas.

Ini berarti crawler mesin pencari tidak akan mengalami masalah.

Cheers, saya harap ini membantu
Gray

grayskale.com
sumber
0

Coba ini untuk mencegah klien dari segala jenis pengguliran vertikal di hashchanged (di dalam event handler Anda):

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

(gambar ulang browser)

andy
sumber
0

Memecahkan masalah saya dengan melakukan ini:

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