Як відключити «стрибок» якоря під час завантаження сторінки?


110

Я думаю, що це може бути неможливим, спробую і поясню якнайкраще. У мене є сторінка, що містить вкладки (живлення 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потім показану відповідну вкладку.

сторінка не "стрибає" на якір через "return false".

ця подія запускається лише на події клацання. отже, якщо я відвідую свої «вкладки» з будь-якої іншої сторінки, спрацьовує ефект «стрибка». Для боротьби з цим я автоматично прокручую до початку сторінки, але я вважаю, що цього не сталося.

чи є якийсь спосіб імітувати "повернути помилкове", коли сторінка завантажується, запобігаючи виникненню "стрибка" якоря.

сподіваюся, що це досить зрозуміло.

Дякую

Відповіді:


143

Виправлення не працює? Я не впевнений, чи правильно я розумію питання - чи є у вас демонстраційна сторінка? Ви можете спробувати:

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, але приємно залишати це так, що браузерам, можливо, не доведеться нічого робити. Також нагадує, для чого призначений прокруткаTo!
dave1010

2
Сьогодні у мене була ця сама проблема. Я фактично повинен був додати хеш (ідентичний іменам табуляцій / значень href) до своїх посилань nav. Я в кінцевому підсумку додав до моїх вкладок суфікс 1-char, а потім підставив значення на 1 char (str.slice (0, -1) при порівнянні їх з window.location.hash. Таким чином хеші відрізняються, і стрибки не виникають .
розробник10

1
ifПовинен бути зовні, а не всередині. також мінімум для інтервалу становить приблизно 10, тому 0 або 1 - це те саме .. як 10. залежно від браузера.
vsync

2
Це не заважає браузер , щоб перейти до хештегом, ви повинні поставити порожній хештегом , щоб запобігти «jumpieness», побачити моя відповідь тут 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-висоти в у div з дійсно довгим списком, FFбув прокрутити вниз там, де буде прихований вузол у домі. Це використовувало лише перші три рядки фактичного коду (а не коментарі), і це виправляло мою проблему з FireFox.
JQII

12

Є й інші способи відстеження того, на якій вкладці ви перебуваєте; можливо встановлення файлу cookie або значення у прихованому полі тощо тощо.

Я б сказав, що якщо ви не хочете, щоб сторінка перескакувала при завантаженні, вам було б краще скористатися одним із цих інших варіантів, а не хеш, тому що головна причина використання хешу, який надає перевагу їм, - це дозволяти саме те, що ви Ви хочете заблокувати.

Ще один момент - сторінка не перескакує, якщо ваші хеш-посилання не відповідають назвам тегів у документі, тому, можливо, якщо ви хочете продовжувати використовувати хеш, ви можете маніпулювати вмістом, щоб теги були названі по-іншому. Якщо ви використовуєте послідовний префікс, ви все одно зможете використовувати 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 = хеш, браузер не скаче.

  2. Створіть сценарій, який перевіряє хеш в URL-адресі, а потім знаходить і показує елемент prrpo prime (який приховано за замовчуванням).

  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

Дякую за це! Також єдине рішення, яке працювало на мене після години спроб, але найкраща частина цього рішення для мене - це те, що мені не потрібно видаляти хеш.
Кріс Веккіо

Це не спрацює, якщо скроллер вже знаходиться вгорі сторінки на завантаженні сторінки, тоді він буде прокручуватися вниз, як зазвичай, і після того, як сторінка буде зроблена, вона перестрибує вгору. Хтось знає, як це так?
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
}

soooooo розумний!
duhaime

3

Хоча прийнята відповідь працює добре, я виявив, що іноді, особливо на сторінках, що містять великі зображення, на яких смуга прокрутки дико скаче, використовуючи

 window.scrollTo(0, 0);

Що може бути досить відволікаючим для користувача.

Рішення, на якому я вирішив, врешті-решт, насправді досить простий, і це використовувати інший ідентифікатор на цілі, ніж той, що використовується в location.hash

Наприклад:

Ось посилання на іншій сторінці

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

Звичайно, якщо tab2на сторінці вкладок є елемент з ідентифікатором, вікно перескакує на нього при завантаженні.

Тож ви можете додати щось до ідентифікатора, щоб запобігти цьому:

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

І тоді ви можете додати "-noScroll"до location.hashв 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

У моєму випадку через використання прив’язного посилання для спливаючого вікна CSS я використав такий спосіб:

Просто збережіть сторінкуYOffset спочатку при натисканні, а потім встановіть для цього ScrollTop:

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

Після спроб інших рішень це те, що працювало для мене, у моєму випадку веб-сайт, з яким я працював, використовував # у URL-адресі для завантаження певного розділу каси. Замість того, щоб змінювати функцію оформлення каси для хешу в URL-адресі, я просто використав це. Спасибі
chris c

1

Я думаю, що я знайшов спосіб для вкладок інтерфейсу користувача, не повторюючи функціональність. Поки що я не знайшов жодних проблем.

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

На жаль, це все дуже глючно.


тому що onload працює після того, як все буде завантажено повністю, включаючи фотографії ... так, звичайно, це так
глючно

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

Вирішив мій промлем, зробивши це:

// 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);
});`
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.