Làm cách nào để tắt “jump” neo khi tải trang?


110

Tôi nghĩ điều này có thể không được, sẽ cố gắng và giải thích tốt nhất có thể. Tôi có một trang chứa các tab (được hỗ trợ bởi jquery), được điều khiển bởi những thứ sau:

Tôi đang sử dụng mã này, do một người dùng khác cung cấp từ một câu hỏi trước.

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

mã này hoạt động tốt khi tôi truy cập trực tiếp vào trang "tab".

tuy nhiên, tôi cần liên kết đến các tab không mong muốn từ các trang khác - vì vậy để làm điều này, mã sẽ window.location.hashhiển thị tab phê duyệt sau đó.

trang không "nhảy" đến liên kết vì "return false".

Tuy nhiên, sự kiện này chỉ được kích hoạt trên một sự kiện nhấp chuột. do đó, nếu tôi truy cập các "tab" của mình từ bất kỳ trang nào khác, hiệu ứng "nhảy" sẽ được kích hoạt. Để chống lại điều này, tôi tự động cuộn lên đầu trang, nhưng tôi thà rằng điều này không xảy ra.

có cách nào để mô phỏng "return false" khi tải trang, ngăn chặn "bước nhảy" neo xảy ra không.

hy vọng điều này là đủ rõ ràng.

cảm ơn

Câu trả lời:


143

Sửa chữa của bạn không hoạt động? Tôi không chắc mình có hiểu đúng câu hỏi không - bạn có trang demo không? Bạn có thể thử:

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

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

Chỉnh sửa: đã thử nghiệm và hoạt động trên Firefox, IE & Chrome trên Windows.
Chỉnh sửa 2: di chuyển setTimeout()bên trong ifkhối, đạo cụ @vsync.


2
anh hùng! Có, "bản sửa lỗi" của tôi đã hoạt động, nhưng trang sẽ "cuộn" (như mã của tôi đã nói với nó), và tôi thà rằng nó không cuộn. mã của bạn hoạt động hoàn hảo. Tôi chưa xem ScrollTo - chức năng này có cần thiết không? nó dường như hoạt động tốt chỉ với window.scrollTo (0, 0);
Ross

3
Tôi đã thử nó trong Firefox trên một trang trống không có setTimeoutvà nó không phải lúc nào cũng hoạt động. Bạn có thể không cần nó nếu nó ở trong jQuery $(function() {. Bạn không thực sự cần location.hash, nhưng thật tuyệt khi để nó ở đó để các trình duyệt có thể không phải làm gì cả. Cũng nhắc nhở bạn scrollTo dùng để làm gì!
dave1010

2
Hôm nay tôi đã có cùng một vấn đề. Tôi thực sự phải thêm hàm băm (giống với tên tab / giá trị href) vào các liên kết điều hướng của mình. Tôi đã kết thúc việc thêm hậu tố 1-char vào các tab của mình và sau đó xâu chuỗi các giá trị bằng 1 ký tự (str.slice (0, -1) khi so sánh chúng với window.location.hash Bằng cách này, các hàm băm khác nhau và không xảy ra hiện tượng nhảy) .
nhà phát triển 10

1
Cái ifnên ở bên ngoài, không phải bên trong. Ngoài ra, khoảng thời gian tối thiểu là khoảng 10, vì vậy 0 hoặc 1 là như nhau..và 10. tùy thuộc vào trình duyệt.
vsync

2
Điều này KHÔNG ngăn trình duyệt chuyển đến thẻ bắt đầu bằng #, bạn phải đặt thẻ bắt đầu bằng # trống để ngăn chặn tình trạng 'giật tít', hãy xem câu trả lời của tôi tại đây stackoverflow.com/a/29823913/826194
Larzan,

43

Xem câu trả lời của tôi tại đây: Câu trả lời Stackoverflow

Bí quyết là chỉ cần xóa thẻ bắt đầu bằng # càng sớm càng tốt và lưu trữ giá trị của nó để sử dụng cho riêng bạn:

Điều quan trọng là bạn không đặt phần mã đó trong các hàm $ () hoặc $ (window) .load () vì nó sẽ quá muộn và trình duyệt đã chuyển đến thẻ.

// 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
tôi đã gặp lỗi với FF trong đó tôi đang sử dụng max-height tràn-y trên một div có danh sách thực sự dài, FF sẽ cuộn xuống nơi nút ẩn sẽ nằm trong dom. Điều này chỉ sử dụng ba dòng mã thực tế hàng đầu (không phải nhận xét) và điều này đã khắc phục sự cố của tôi với FireFox.
JQII

12

Có những cách khác để theo dõi bạn đang ở trên tab nào; có lẽ đặt cookie hoặc giá trị trong trường ẩn, v.v.

Tôi sẽ nói rằng nếu bạn không muốn trang nhảy khi tải, tốt hơn hết bạn nên sử dụng một trong những tùy chọn khác này thay vì sử dụng hàm băm, bởi vì lý do chính để sử dụng hàm băm ưu tiên cho chúng là cho phép chính xác những gì bạn đang muốn chặn.

Một điểm khác - trang sẽ không nhảy nếu các liên kết băm của bạn không khớp với tên của các thẻ trong tài liệu, vì vậy có lẽ nếu bạn muốn tiếp tục sử dụng hàm băm, bạn có thể thao tác nội dung để các thẻ được đặt tên khác nhau. Nếu bạn sử dụng một tiền tố nhất quán, bạn vẫn có thể sử dụng Javascript để chuyển giữa các tiền tố đó.

Hy vọng rằng sẽ giúp.


2
Điểm tốt. Đừng quên cố gắng giữ cho trang có thể sử dụng / có thể truy cập được khi tắt JS / CSS.
dave1010

12

Tôi đã sử dụng giải pháp của dave1010, nhưng hơi khó khăn khi tôi đặt nó vào bên trong hàm $ (). Ready. Vì vậy, tôi đã làm điều này: (không bên trong $ (). 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);
    }

10
  1. Trình duyệt chuyển đến <element id="abc" />nếu có http://site.com/#abc băm trong địa chỉ và phần tử có id = "abc" hiển thị. Vì vậy, bạn chỉ nên ẩn các yếu tố theo mặc định: <element id="anchor" style="display: none" />. Nếu không có phần tử hiển thị có id = hash trên trang, trình duyệt sẽ không nhảy.

  2. Tạo một tập lệnh kiểm tra băm trong url, sau đó tìm và hiển thị phần tử prrpopriate (phần tử này bị ẩn theo mặc định).

  3. Tắt hành vi "liên kết dạng băm" mặc định bằng cách liên kết sự kiện onclick với một liên kết và chỉ định return false;là kết quả của sự kiện onclick.

Khi tôi triển khai các tab, tôi đã viết một cái gì đó như thế:

    <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

Không có câu trả lời nào không hoạt động đủ tốt đối với tôi, tôi thấy trang nhảy đến neo và sau đó lên đầu cho một số giải pháp, một số câu trả lời không hoạt động chút nào, có thể mọi thứ đã thay đổi trong nhiều năm. Hy vọng chức năng của tôi sẽ giúp ích cho ai đó.

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

Giải pháp tốt nhất mà tôi tìm thấy cho đến nay. Và thực sự đã thấy rất nhiều.
MarkSkayff

Cảm ơn vì điều này! Cũng là giải pháp duy nhất phù hợp với tôi sau nhiều giờ cố gắng, nhưng phần tốt nhất của giải pháp này đối với tôi là tôi không phải xóa hàm băm.
Chris Vecchio

Điều này không hoạt động nếu con lăn đã ở đầu trang khi tải trang sau đó nó sẽ cuộn xuống như bình thường và sau khi trang xong nó sẽ nhảy lên đầu trang. Bất cứ ai biết cách này là trường hợp?
robgha01

@ robgha01 vui lòng đảm bảo rằng hàm đó được thực thi càng sớm càng tốt và không đợi bất kỳ sự kiện nào, điều này là sai : $(document).ready(function () { preventAnchorScroll(); });, chỉ cần gọi hàm ngay từ đầu JavaScript của bạn. Tôi đã thử nghiệm nó ngay bây giờ, hoạt động cho tôi trên Chrome, Firefox và Opera.
kdmitry

4

CSS bẩn chỉ sửa để luôn được cuộn lên mỗi khi sử dụng neo (không hữu ích nếu bạn vẫn muốn sử dụng neo để cuộn-nhảy, rất hữu ích cho liên kết sâu):

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

thật thông minh!
duhaime

3

Mặc dù câu trả lời được chấp nhận hoạt động tốt nhưng đôi khi tôi nhận thấy rằng đôi khi, đặc biệt là trên các trang có chứa hình ảnh lớn mà thanh cuộn sẽ nhảy lung tung khi sử dụng

 window.scrollTo(0, 0);

Điều này có thể gây mất tập trung cho người dùng.

Giải pháp cuối cùng mà tôi đã giải quyết thực sự khá đơn giản và đó là sử dụng một ID khác trên mục tiêu cho một ID được sử dụng trong location.hash

Ví dụ:

Đây là liên kết trên một số trang khác

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

Vì vậy, tất nhiên nếu có một phần tử có ID tab2trên trang tab, cửa sổ sẽ chuyển đến phần tử đó khi tải.

Vì vậy, bạn có thể thêm một cái gì đó vào ID để ngăn chặn nó:

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

Và sau đó bạn có thể thêm "-noScroll"vào location.hashtrong 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>

2

Trong trường hợp của tôi vì sử dụng liên kết neo cho cửa sổ bật lên CSS, tôi đã sử dụng cách này:

Chỉ cần lưu trangYOffset điều đầu tiên khi nhấp chuột và sau đó đặt ScrollTop thành:

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

Sau khi thử các giải pháp khác, đây là giải pháp phù hợp với tôi, trong trường hợp của tôi, trang web tôi đang làm việc đã sử dụng # trong url để tải một phần cụ thể của thanh toán. Thay vì sửa đổi chức năng thanh toán cho băm trong url tôi vừa sử dụng cái này. Cảm ơn
chris c

1

Tôi nghĩ rằng tôi đã tìm ra cách cho các Tab giao diện người dùng mà không cần làm lại chức năng. Cho đến nay tôi đã không tìm thấy bất kỳ vấn đề.

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

Tất cả trong một sự kiện đã sẵn sàng. Nó thêm "tab_" cho hàm băm nhưng hoạt động cả khi được nhấp và trang được tải bằng hàm băm.


1

Điều này sẽ hoạt động với 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

Cách tiếp cận khác

Hãy thử kiểm tra xem trang đã được cuộn chưa và sau đó đặt lại vị trí:

var scrolled = false;

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

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

Heres a demo


không hoạt động anh em ơi ... tải ban đầu ở dưới cùng ... sau khi làm mới nó vẫn ở trên cùng
Martin Zvarík

0

Tôi đã không thành công với các setTimeoutphương pháp trên trong Firefox.

Thay vì setTimeout, tôi đã sử dụng một hàm onload:

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

Rất tiếc, nó vẫn còn rất trục trặc.


bởi vì onload chạy sau khi mọi thứ được tải đầy đủ, bao gồm cả ảnh ... nên tất nhiên theo cách này nó sẽ trục trặc
Martin Zvarík

0

Tôi đã không có bất kỳ thành công nhất quán nào với các giải pháp này.

Rõ ràng là do bước nhảy xảy ra trước Javascript => tham chiếu ( http://forum.jquery.com/topic/preventing-anchor-jump )

Giải pháp của tôi là đặt tất cả các neo ở trên cùng theo mặc định bằng CSS.

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

Sau đó, sử dụng jquery để cuộn đến cha mẹ của anchor đích hoặc một thẻ anh chị em (có thể là một thẻ em trống)

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

ví dụ về jquery để cuộn khi URL được nhập với hàm băm
(trang không được tải trong cửa sổ / tab, điều này bao gồm các liên kết từ các nguồn khác / bên ngoài)

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

Ngoài ra, bạn sẽ muốn ngăn mặc định cho các nhấp chuột cố định khi ở trên trang và sau đó cuộn đến mục tiêu của chúng

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

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

Điều tốt về phương pháp này là các mục tiêu thẻ liên kết, vẫn có cấu trúc bên cạnh nội dung có liên quan, mặc dù vị trí CSS của chúng ở trên cùng.

Điều này có nghĩa là các trình thu thập thông tin của công cụ tìm kiếm sẽ không gặp sự cố.

Chúc mừng, tôi hy vọng điều này sẽ giúp
Grey


0

Hãy thử điều này để ngăn khách hàng khỏi bất kỳ loại cuộn dọc nào trên hashchanged (bên trong trình xử lý sự kiện của bạn):

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

(trình duyệt vẽ lại)


0

Giải quyết vấn đề của tôi bằng cách làm điều này:

// 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);
});`
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.