จะปิดการใช้งาน Anchor“ Jump” เมื่อโหลดเพจได้อย่างไร?


111

ฉันคิดว่าสิ่งนี้อาจเป็นไปไม่ได้จะพยายามอธิบายให้ดีที่สุดเท่าที่จะทำได้ ฉันมีหน้าที่มีแท็บ (ขับเคลื่อนด้วย jquery) ซึ่งควบคุมโดยสิ่งต่อไปนี้:

ฉันใช้รหัสนี้ตามที่ผู้ใช้รายอื่นให้ไว้จากคำถามก่อนหน้านี้

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

รหัสนี้ใช้งานได้ดีเมื่อฉันไปที่หน้า "แท็บ" โดยตรง

อย่างไรก็ตามฉันจำเป็นต้องเชื่อมโยงไปยังแท็บที่ไม่ถูกต้องจากหน้าอื่นดังนั้นในการทำเช่นนี้รหัสจะได้รับwindow.location.hashจากนั้นจะแสดงแท็บที่เหมาะสม

หน้าเว็บไม่ "ข้าม" ไปที่จุดยึดเนื่องจาก "คืนค่าเท็จ"

อย่างไรก็ตามเหตุการณ์นี้จะถูกทริกเกอร์ในเหตุการณ์การคลิกเท่านั้น ดังนั้นหากฉันไปที่ "แท็บ" ของฉันจากหน้าอื่น ๆ เอฟเฟกต์ "กระโดด" จะถูกเรียกใช้ เพื่อต่อสู้กับสิ่งนี้ฉันเลื่อนไปที่ด้านบนของหน้าโดยอัตโนมัติ แต่ฉันคิดว่าสิ่งนี้จะไม่เกิดขึ้น

มีวิธีใดบ้างในการจำลอง "คืนค่าเท็จ" เมื่อโหลดหน้าเว็บเพื่อป้องกันไม่ให้จุดยึด "กระโดด" เกิดขึ้น

หวังว่านี่จะชัดเจนพอ

ขอบคุณ

คำตอบ:


144

การแก้ไขของคุณไม่ได้ผลหรือไม่? ฉันไม่แน่ใจว่าเข้าใจคำถามถูกต้องหรือไม่ - คุณมีหน้าสาธิตหรือไม่? คุณสามารถลอง:

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

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

แก้ไข: ทดสอบแล้วและใช้งานได้ใน Firefox, IE & Chrome บน Windows
แก้ไข 2: ย้ายsetTimeout()เข้าไปในifบล็อกอุปกรณ์ประกอบฉาก @vsync


2
ฮีโร่! ใช่ "แก้ไข" ของฉันใช้งานได้ แต่หน้าจะ "เลื่อน" (ตามที่รหัสของฉันบอกให้) และฉันไม่อยากจะเลื่อน รหัสของคุณทำงานได้อย่างสมบูรณ์ ฉันไม่ได้ดู ScrollTo - ฟังก์ชันนี้จำเป็นหรือไม่ ดูเหมือนว่าจะทำงานได้ดีเพียงแค่ window.scrollTo (0, 0);
รอส

3
ฉันลองใช้ใน Firefox บนหน้าที่ว่างเปล่าโดยไม่มีsetTimeoutและมันก็ไม่ได้ผลเสมอไป คุณอาจไม่จำเป็นต้องใช้มันถ้ามันอยู่ในของ jQuery $(function() {อยู่แล้ว คุณไม่จำเป็นต้องใช้จริงๆlocation.hashแต่เป็นการดีที่จะทิ้งไว้ในเบราว์เซอร์จึงไม่ต้องทำอะไรเลย ยังช่วยเตือนคุณว่า scrollTo มีไว้เพื่ออะไร!
dave1010

2
วันนี้ฉันมีปัญหาเดียวกันนี้ ฉันต้องเพิ่มแฮช (เหมือนกับชื่อแท็บ / ค่า href) ในลิงก์นำทางของฉัน ฉันลงเอยด้วยการเพิ่มคำต่อท้าย 1 char ลงในแท็บของฉันจากนั้นเปลี่ยนค่าด้วย 1 char (str.slice (0, -1) เมื่อเปรียบเทียบกับ window.location.hash วิธีนี้แฮชจะแตกต่างกันและไม่มีการกระโดดเกิดขึ้น .
พัฒนา 10

1
ifควรจะออกไปข้างนอกไม่ได้อยู่ใน นอกจากนี้ค่าต่ำสุดสำหรับช่วงเวลาคือประมาณ 10 ดังนั้น 0 หรือ 1 จึงเท่ากัน .. และ 10 ขึ้นอยู่กับเบราว์เซอร์
vsync

2
สิ่งนี้ไม่ได้ป้องกันไม่ให้เบราว์เซอร์ข้ามไปที่แฮชแท็กคุณต้องใส่แฮชแท็กที่ว่างเปล่าเพื่อป้องกัน 'ความโดดเด่น' ดูคำตอบของฉันที่นี่stackoverflow.com/a/29823913/826194
Larzan

43

ดูคำตอบของฉันที่นี่: คำตอบ Stackoverflow

เคล็ดลับคือเพียงแค่ลบแฮชแท็ก ASAP และเก็บมูลค่าไว้สำหรับการใช้งานของคุณเอง:

สิ่งสำคัญคือคุณต้องไม่ใส่ส่วนนั้นของโค้ดในฟังก์ชัน $ () หรือ $ (window) .load () เพราะมันจะสายเกินไปและเบราว์เซอร์ได้ย้ายไปที่แท็กแล้ว

// 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 () {});
    }
});

1
ฉันเจอบั๊กกับ FF โดยที่ฉันใช้ max-height overflow-y บน div ที่มีรายการยาวมาก FF จะเลื่อนลงไปที่โหนดที่ซ่อนอยู่จะอยู่ในโดม สิ่งนี้ใช้เพียงสามบรรทัดแรกของรหัสจริง (ไม่ใช่ความคิดเห็น) และสิ่งนี้แก้ไขปัญหาของฉันกับ FireFox
JQII

12

มีวิธีอื่น ๆ ในการติดตามว่าคุณอยู่บนแท็บใด อาจตั้งค่าคุกกี้หรือค่าในฟิลด์ที่ซ่อนอยู่ ฯลฯ เป็นต้น

ฉันจะบอกว่าถ้าคุณไม่ต้องการให้หน้าเว็บโหลดคุณจะดีกว่าถ้าใช้ตัวเลือกอื่น ๆ เหล่านี้แทนที่จะใช้แฮชเพราะเหตุผลหลักในการใช้แฮชตามความต้องการของพวกเขาคือเพื่อให้สิ่งที่คุณต้องการ กำลังต้องการที่จะปิดกั้น

อีกประเด็นหนึ่ง - หน้าจะไม่กระโดดหากลิงก์แฮชของคุณไม่ตรงกับชื่อของแท็กในเอกสารดังนั้นหากคุณต้องการใช้แฮชต่อไปคุณสามารถปรับเปลี่ยนเนื้อหาเพื่อให้แท็กตั้งชื่อแตกต่างกันได้ หากคุณใช้คำนำหน้าที่สอดคล้องกันคุณจะยังคงสามารถใช้ Javascript เพื่อข้ามไปมาระหว่างนั้นได้

หวังว่าจะช่วยได้


2
จุดที่ดี อย่าลืมพยายามทำให้เพจใช้งานได้ / เข้าถึงได้โดยปิด JS / CSS
dave1010

12

ฉันใช้โซลูชันของ dave1010 แต่มันค่อนข้างน่ากลัวเมื่อใส่ไว้ในฟังก์ชัน $ () พร้อม ฉันจึงทำสิ่งนี้: (ไม่อยู่ใน $ () พร้อม)

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

10
  1. เบราว์เซอร์จะข้ามไป<element id="abc" />หากมีแฮชhttp://site.com/#abcในที่อยู่และองค์ประกอบที่มี id = "abc" จะปรากฏขึ้น <element id="anchor" style="display: none" />ดังนั้นคุณก็ควรจะซ่อนองค์ประกอบโดยเริ่มต้น: หากไม่มีองค์ประกอบที่มองเห็นได้พร้อม id = hash ที่หน้าเบราว์เซอร์จะไม่กระโดด

  2. สร้างสคริปต์ที่ตรวจสอบแฮชใน url จากนั้นค้นหาและแสดงองค์ประกอบ prrpopriate (ซึ่งถูกซ่อนไว้โดยค่าเริ่มต้น)

  3. ปิดใช้งานพฤติกรรม "แฮชเหมือนลิงก์" เริ่มต้นโดยผูกเหตุการณ์ onclick เข้ากับลิงก์และระบุreturn false;เป็นผลลัพธ์ของเหตุการณ์ onclick

เมื่อฉันติดตั้งแท็บฉันเขียนอะไรทำนองนั้น:

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

6

ไม่มีคำตอบใดที่ทำงานได้ไม่ดีพอสำหรับฉันฉันเห็นหน้าเว็บกระโดดไปที่จุดยึดและจากนั้นขึ้นไปด้านบนสำหรับวิธีแก้ปัญหาบางคำตอบไม่ได้ผลเลยอาจมีการเปลี่ยนแปลงหลายปี หวังว่าฟังก์ชันของฉันจะช่วยใครบางคนได้

/**
 * 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
        );
    });
}

ทางออกที่ดีที่สุดที่ฉันพบจนถึงตอนนี้ และเห็นจริงมากมาย.
MarkSkayff

ขอบคุณสำหรับสิ่งนี้! นอกจากนี้วิธีแก้ปัญหาเท่านั้นที่ได้ผลสำหรับฉันหลังจากผ่านไปหลายชั่วโมง แต่ส่วนที่ดีที่สุดของวิธีแก้ปัญหานี้สำหรับฉันคือฉันไม่ต้องลบแฮช
Chris Vecchio

สิ่งนี้จะไม่ได้ผลหาก scroller อยู่ที่ด้านบนสุดของหน้าในการโหลดหน้าแล้วมันจะเลื่อนลงเหมือนปกติและหลังจากทำหน้าเสร็จมันก็จะกระโดดขึ้นไปด้านบน ใครรู้วิธีนี้เป็นกรณีนี้?
robgha01

@ robgha01 โปรดตรวจสอบให้แน่ใจว่าฟังก์ชันถูกเรียกใช้งานโดยเร็วที่สุดและไม่ต้องรอให้เกิดเหตุการณ์ใด ๆ สิ่งนี้ไม่ถูกต้อง: $(document).ready(function () { preventAnchorScroll(); });เพียงแค่เรียกใช้ฟังก์ชันที่จุดเริ่มต้นของ JavaScript ของคุณ ฉันทดสอบแล้วใช้งานได้กับฉันใน Chrome, Firefox และ Opera
kdmitry

4

CSS สกปรกแก้ไขเฉพาะเพื่อให้เลื่อนขึ้นทุกครั้งที่ใช้จุดยึด (ไม่มีประโยชน์หากคุณยังต้องการใช้จุดยึดสำหรับการเลื่อนแบบเลื่อนซึ่งมีประโยชน์มากสำหรับการลิงก์ในรายละเอียด):

.elementsWithAnchorIds::before {
   content: "";
   display: block;
   height: 9999px;
   margin-top: -9999px; //higher thin page height
}

ฉลาดมาก!
duhaime

3

แม้ว่าคำตอบที่ได้รับการยอมรับจะทำงานได้ดี แต่ฉันพบว่าบางครั้งโดยเฉพาะในหน้าที่มีภาพขนาดใหญ่ที่แถบเลื่อนจะกระโดดไปมาอย่างรุนแรงโดยใช้

 window.scrollTo(0, 0);

ซึ่งอาจทำให้ผู้ใช้เสียสมาธิได้มากทีเดียว

วิธีแก้ปัญหาที่ฉันตัดสินในตอนท้ายนั้นค่อนข้างง่ายและนั่นคือการใช้ ID ที่แตกต่างกันในเป้าหมายกับรหัสที่ใช้ใน location.hash

เช่น:

นี่คือลิงค์ในหน้าอื่น ๆ

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

ดังนั้นแน่นอนว่าหากมีองค์ประกอบที่มี ID tab2บนหน้าแท็บหน้าต่างจะข้ามไปที่มันเมื่อโหลด

ดังนั้นคุณสามารถต่อท้ายบางอย่างกับ ID เพื่อป้องกัน:

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

และจากนั้นคุณสามารถผนวก"-noScroll"การlocation.hashในจาวาสคริปต์:

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

2

ในกรณีของฉันเนื่องจากการใช้ anchor link สำหรับ CSS popup ฉันใช้วิธีนี้:

เพียงแค่บันทึก pageYOffset สิ่งแรกเมื่อคลิกจากนั้นตั้งค่า ScrollTop เป็น:

$(document).on('click','yourtarget',function(){
        var st=window.pageYOffset;
        $('html, body').animate({
                'scrollTop' : st
            });
});

หลังจากลองใช้วิธีแก้ปัญหาอื่นแล้วนี่เป็นวิธีที่ใช้ได้ผลสำหรับฉันในกรณีของฉันเว็บไซต์ที่ฉันกำลังทำงานอยู่ใช้ # ใน url เพื่อโหลดส่วนเฉพาะของการชำระเงิน แทนที่จะแก้ไขฟังก์ชันการชำระเงินสำหรับแฮชใน URL ที่ฉันเพิ่งใช้สิ่งนี้ ขอบคุณ
chris c

1

ฉันคิดว่าฉันพบวิธีสำหรับแท็บ UI โดยไม่ต้องทำซ้ำฟังก์ชัน จนถึงตอนนี้ยังไม่พบปัญหาใด ๆ

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

ทั้งหมดภายในงานพร้อม มันนำหน้า "tab_" สำหรับแฮช แต่จะทำงานได้ทั้งเมื่อคลิกและหน้าที่โหลดด้วยแฮช


1

สิ่งนี้จะใช้ได้กับ 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>


0

อีกแนวทางหนึ่ง

ลองตรวจสอบว่ามีการเลื่อนหน้าหรือไม่จากนั้นรีเซ็ตตำแหน่งเท่านั้น:

var scrolled = false;

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

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

Heres a demo


ไม่ทำงานครับ ... โหลดเริ่มต้นอยู่ที่ด้านล่าง ... หลังจากรีเฟรชแล้วจะอยู่ด้านบน
Martin Zvarík

0

ฉันไม่ประสบความสำเร็จมากนักกับsetTimeoutวิธีการข้างต้นใน Firefox

แทนที่จะเป็น setTimeout ฉันใช้ฟังก์ชัน onload:

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

มันยังคงผิดพลาดอยู่มาก แต่น่าเสียดาย


เนื่องจากการโหลดทำงานหลังจากที่ทุกอย่างโหลดจนเต็มรวมถึงภาพถ่าย ... แน่นอนว่ามันผิดพลาดด้วยวิธีนี้
Martin Zvarík

0

ฉันไม่ประสบความสำเร็จอย่างสม่ำเสมอกับโซลูชันเหล่านี้

เห็นได้ชัดว่าเกิดจากการกระโดดก่อน Javascript => การอ้างอิง ( http://forum.jquery.com/topic/preventing-anchor-jump )

วิธีแก้ปัญหาของฉันคือวางตำแหน่งจุดยึดทั้งหมดไว้ที่ด้านบนโดยค่าเริ่มต้นด้วย CSS

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

จากนั้นใช้ jquery เพื่อเลื่อนไปที่หลักของจุดยึดเป้าหมายหรือพี่น้อง (อาจเป็นแท็ก em ว่าง)

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

ตัวอย่าง jquery สำหรับการเลื่อนเมื่อป้อน URL ด้วยแฮช
(ต้องไม่โหลดหน้าในหน้าต่าง / แท็บซึ่งจะครอบคลุมลิงก์จากแหล่งอื่น / ภายนอก)

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

นอกจากนี้คุณจะต้องป้องกันไม่ให้ค่าเริ่มต้นสำหรับการคลิกจุดยึดขณะอยู่บนหน้าจากนั้นเลื่อนไปที่เป้าหมาย

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

และ 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;
});

สิ่งที่ดีเกี่ยวกับวิธีนี้คือเป้าหมายแท็กจุดยึดซึ่งยังคงมีโครงสร้างอยู่ข้างเนื้อหาที่เกี่ยวข้องแม้ว่าตำแหน่ง CSS จะอยู่ที่ด้านบนสุดก็ตาม

นี่ควรหมายความว่าโปรแกรมรวบรวมข้อมูลของเครื่องมือค้นหาจะไม่มีปัญหา

ไชโยฉันหวังว่านี่จะช่วย
เกรย์ได้


0

ลองใช้วิธีนี้เพื่อป้องกันไม่ให้ไคลเอ็นต์เลื่อนตามแนวตั้งใด ๆ เมื่อมีการเปลี่ยนแปลง (ภายในตัวจัดการเหตุการณ์ของคุณ):

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

(เบราว์เซอร์วาดใหม่)


0

แก้ไข Promlem ของฉันโดยทำสิ่งนี้:

// 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);
});`
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.