开发者

How to disable anchor "jump" when loading a page?

I think this may not be possible, will try and explain as best as I can. I have a page containing tabs (jquery powered), controlled by the following:

I'm using this code, as provided by another user from a previous question.

开发者_高级运维
<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>

this code works great when I visit the "tabs" page directly.

however, I need to link to invidual tabs from other pages - so to do this, the code gets the window.location.hash then shows the appropiate tab.

the page doesn't "jump" to the anchor because of "return false".

this event is only triggered on a click event however. hence, if i visit my "tabs" from any other page, the "jump" effect is triggered. To combat this I automatically scroll to teh top of the page, but I would rather this didn't happen.

is there any way to simulate "return false" when the page loads, preventing the anchor "jump" from occuring.

hope this is clear enough.

thanks


Does your fix not work? I'm not sure if I understand the question correctly - do you have a demo page? You could try:

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

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

Edit: tested and works in Firefox, IE & Chrome on Windows.
Edit 2: move setTimeout() inside if block, props @vsync.


See my answer here: Stackoverflow Answer

The trick is to just remove the hashtag ASAP and store its value for your own use:

It is important that you do not put that part of the code in the $() or $(window).load() functions as it would be too late and the browser already has moved to the 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 () {});
    }
});


There are other ways of tracking what tab you're on; perhaps setting a cookie, or a value in a hidden field, etc etc.

I would say that if you don't want the page jumping on load, you would be better off using one of these other options rather than the hash, because the main reason for using the hash in preference to them is to allow exactly what you're wanting to block.

Another point - the page won't jump if your hash links don't match the names of the tags in the document, so perhaps if you want to keep using the hash you could manipulate the content so that the tags are named differently. If you use a consistent prefix, you will still be able to use Javascript to jump between then.

Hope that helps.


I used dave1010's solution, but it was a bit jumpy when I put it inside the $().ready function. So I did this: (not inside the $().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);
    }


  1. Browser jumps to <element id="abc" /> if there are http://site.com/#abc hash in the address and the element with id="abc" is visible. So, you just should hide the element by default: <element id="anchor" style="display: none" />. If there is no visible element with id=hash at the page, the browser would not jump.

  2. Create a script that checks the hash in url, and then finds and shows the prrpopriate element (that is hidden by default).

  3. Disable default "hash-like link" behaviour by binding an onclick event to a link and specify return false; as a result of onclick event.

When I implemented tabs, I wrote something like that:

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


None of answers do not work good enough for me, I see page jumping to anchor and then to top for some solutions, some answers do not work at all, may be things changed for years. Hope my function will help to someone.

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


dirty CSS only fix to stay scrolled up every time the anchor is used (not useful if you still want to use anchors for scroll-jumps, very useful for deeplinking):

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


While the accepted answer does work well, I did find that sometimes, especially on pages containing large images that the scroll bar will jump about wildly using

 window.scrollTo(0, 0);

Which can be quite distracting for the user.

The solution I settled on in the end is actually pretty simple, and that's to use a different ID on the target to the one used in location.hash

Eg:

Here is the link on some other page

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

So of course if there is an element with an ID of tab2 on the tabs page the window will jump to it on load.

So you can append something to the ID to prevent it:

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

And then you can append "-noScroll" to location.hash in the 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>


In my case because of using anchor link for CSS popup I've used this way:

Just save the pageYOffset first thing on click and then set the ScrollTop to that:

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


I think I've found a way for UI Tabs without redoing the functionality. So far I haven't found any problems.

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

All within a ready event. It prepends "tab_" for the hash but work both when clicked and page loaded with hash.


This will work with 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>


Another approach

Try checking if the page has been scrolled and only then reset position:

var scrolled = false;

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

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

Heres a demo


I did not have much success with the above setTimeout methods in Firefox.

Instead of a setTimeout, I've used an onload function:

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

It's still very glitchy, unfortunately.


I have not had any consistent success with these solutions.

Apparently due to the fact that the jump happens before Javascript => reference(http://forum.jquery.com/topic/preventing-anchor-jump)

My solution is to position all anchors at the top by default with CSS.

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

Then use jquery to scroll to the parent of the target anchor, or a sibling(maybe an empty em tag)

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

jquery example for scrolling for when URL is entered with hash
(page must not be already loaded in window/tab, this covers links from other/outside sources)

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

Also you'll want to prevent default for anchor clicks while on the page and then scroll to their targets

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

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

The good thing about this method is the anchor tag targets, remain structurally beside the relevant content, although their CSS position is at the top.

This should mean that search engine crawlers won't have a problem.

Cheers, I hope this helps
Gray


Try this to prevent client from any kind of vertical scrolling on hashchanged (inside your event handler):

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

(browser redraw)


Solved my promlem by doing this:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜