पृष्ठ स्क्रॉलिंग के बिना स्थान को संशोधित करना


148

हमें सामग्री में लोड करने के लिए ajax का उपयोग करके कुछ पृष्ठ मिले हैं और कुछ अवसर हैं जहां हमें एक पृष्ठ में गहरी लिंक की आवश्यकता है। "उपयोगकर्ता" के लिए एक लिंक रखने और लोगों को "सेटिंग" पर क्लिक करने के लिए कहने के बजाय यह लोगों को user.aspx # सेटिंग्स से जोड़ने में सक्षम होने के लिए सहायक है

लोगों को हमें वर्गों के लिए सही लिंक प्रदान करने की अनुमति देने के लिए (तकनीकी सहायता, आदि के लिए) मैंने इसे स्वचालित रूप से URL में हैश को संशोधित करने के लिए सेट किया है जब भी एक बटन क्लिक किया जाता है। पाठ्यक्रम का एकमात्र मुद्दा यह है कि जब ऐसा होता है, तो यह पृष्ठ को इस तत्व तक भी स्क्रॉल करता है।

क्या इसे अक्षम करने का कोई तरीका है? नीचे बताया गया है कि मैं यह कैसे कर रहा हूं।

$(function(){
    //This emulates a click on the correct button on page load
    if(document.location.hash){
     $("#buttons li a").removeClass('selected');
     s=$(document.location.hash).addClass('selected').attr("href").replace("javascript:","");
     eval(s);
    }

    //Click a button to change the hash
    $("#buttons li a").click(function(){
            $("#buttons li a").removeClass('selected');
            $(this).addClass('selected');
            document.location.hash=$(this).attr("id")
            //return false;
    });
});

मैंने उम्मीद की थी कि return false;पेज को स्क्रॉल करने से रोका जाएगा - लेकिन यह सिर्फ लिंक को काम नहीं करता है। तो यह अभी के लिए बाहर टिप्पणी की है तो मैं नेविगेट कर सकते हैं।

कोई विचार?

जवाबों:


111

चरण 1: आपको नोड आईडी को परिभाषित करने की आवश्यकता है, जब तक कि हैश सेट नहीं किया गया है। यह हैश सेट होने के दौरान नोड से आईडी को हटाकर किया जाता है, और फिर इसे वापस जोड़ दिया जाता है।

hash = hash.replace( /^#/, '' );
var node = $( '#' + hash );
if ( node.length ) {
  node.attr( 'id', '' );
}
document.location.hash = hash;
if ( node.length ) {
  node.attr( 'id', hash );
}

चरण 2: कुछ ब्राउज़र स्क्रॉल को ट्रिगर करेंगे, जहां आईडीआईडी ​​नोड को अंतिम बार देखा गया था, इसलिए आपको उनकी थोड़ी मदद करने की आवश्यकता है। आपको divव्यूपोर्ट के शीर्ष पर एक अतिरिक्त जोड़ने की जरूरत है , इसकी आईडी को हैश में सेट करें, और फिर सब कुछ वापस रोल करें:

hash = hash.replace( /^#/, '' );
var fx, node = $( '#' + hash );
if ( node.length ) {
  node.attr( 'id', '' );
  fx = $( '<div></div>' )
          .css({
              position:'absolute',
              visibility:'hidden',
              top: $(document).scrollTop() + 'px'
          })
          .attr( 'id', hash )
          .appendTo( document.body );
}
document.location.hash = hash;
if ( node.length ) {
  fx.remove();
  node.attr( 'id', hash );
}

चरण 3: इसे एक प्लग में लपेटें और लिखने के बजाय इसका उपयोग करें location.hash...


1
नहीं, चरण 2 में जो कुछ भी हो रहा है वह यह है कि एक छिपे हुए div को स्क्रॉल के वर्तमान स्थान पर बनाया और रखा गया है। यह वैसी ही है जैसी स्थिति: निश्चित / शीर्ष: 0। इस प्रकार स्क्रॉलबार को उसी स्थान पर "स्थानांतरित" किया जाता है जो वर्तमान में है।
बोरगर

3
यह समाधान वास्तव में अच्छी तरह से काम करता है - हालांकि रेखा: शीर्ष: $: .scroll ()। शीर्ष + 'px' होना चाहिए: शीर्ष: $ (विंडो) .scrollTop () + 'px'
मार्क पर्किन्स

27
यह जानना उपयोगी होगा कि कौन से ब्राउज़र को यहां चरण 2 की आवश्यकता है।
djc

1
धन्यवाद बोर्गर। हालांकि यह मुझे याद है कि आप लक्ष्य नोड के आईडी को हटाने से पहले fx div को जोड़ रहे हैं। इसका मतलब है कि डॉक्यूमेंट में डुप्लिकेट आईडी है। एक संभावित मुद्दे की तरह लगता है, या कम से कम बुरे व्यवहार;)
बेन

1
बहुत बहुत धन्यवाद, इसने भी मेरी मदद की। जब मैंने कार्रवाई की है, तो मैंने एक साइड इफेक्ट भी देखा: मैं अक्सर "मध्य माउस बटन" को लॉक करके स्क्रॉल करता हूं और बस माउस को उस दिशा में ले जाता हूं जहां मैं स्क्रॉल करना चाहता हूं। Google Chrome में यह स्क्रॉल प्रवाह को बाधित करता है। क्या शायद इसके लिए कोई फैंसी वर्कअराउंड है?
YMMD

99

हैश बदलने के लिए * history.replaceStateया का प्रयोग करें history.pushState। यह संबंधित तत्व पर कूद को ट्रिगर नहीं करेगा।

उदाहरण

$(document).on('click', 'a[href^=#]', function(event) {
  event.preventDefault();
  history.pushState({}, '', this.href);
});

JSFiddle पर डेमो

* यदि आप इतिहास को आगे और पीछे समर्थन चाहते हैं

इतिहास व्यवहार

यदि आप उपयोग कर रहे हैं history.pushStateऔर आप पृष्ठ स्क्रॉल नहीं करना चाहते हैं जब उपयोगकर्ता ब्राउज़र के इतिहास बटन (आगे / पीछे) का उपयोग करता है, तो प्रयोगात्मक scrollRestorationसेटिंग (केवल क्रोम 46+) देखें

history.scrollRestoration = 'manual';

ब्राउज़र का समर्थन


5
replaceStateशायद यहाँ जाने का बेहतर तरीका है। यह अंतर pushStateआपके इतिहास में एक आइटम जोड़ता है जबकि replaceStateऐसा नहीं है।
आकिल फर्नांडीस

धन्यवाद @AakilFernandes आप सही हैं। मैंने अभी जवाब अपडेट किया है।
HaNdTriX

यह हमेशा bodyस्क्रॉल नहीं होता है , कभी-कभी ऐसा होता है documentElement। इस देखें सार डिएगो Perini द्वारा
Matijs

1
ie8 / 9 पर कोई विचार यहाँ?
user151496

1
@ user151496 देखें: stackoverflow.com/revisions/…
HaNdTriX

90

मुझे लगता है कि मुझे काफी सरल समाधान मिल गया होगा। समस्या यह है कि URL में हैश उस पृष्ठ पर भी एक तत्व है जिसे आप स्क्रॉल करते हैं। अगर मैं अभी हैश के लिए कुछ पाठ प्रस्तुत करता हूं, तो अब यह एक मौजूदा तत्व का संदर्भ नहीं देता है!

$(function(){
    //This emulates a click on the correct button on page load
    if(document.location.hash){
     $("#buttons li a").removeClass('selected');
     s=$(document.location.hash.replace("btn_","")).addClass('selected').attr("href").replace("javascript:","");
     eval(s);
    }

    //Click a button to change the hash
    $("#buttons li a").click(function(){
            $("#buttons li a").removeClass('selected');
            $(this).addClass('selected');
            document.location.hash="btn_"+$(this).attr("id")
            //return false;
    });
});

अब URL दिखाई देता है page.aspx#btn_elementIDजो पेज पर एक वास्तविक आईडी नहीं है। मैं सिर्फ "btn_" हटाता हूं और वास्तविक तत्व आईडी प्राप्त करता हूं


5
महान समाधान। बहुत का दर्द रहित।
स्वेद

ध्यान दें कि यदि आप किसी कारण से पहले से ही page.aspx # elementID URL के लिए प्रतिबद्ध हैं, तो आप इस तकनीक को उलट सकते हैं और "btn_" को अपनी सभी ID
joshuahedlund

2
यदि आप उपयोग कर रहे हैं तो काम नहीं करता है: सीएसएस में छद्म चयनकर्ताओं को लक्षित करें।
जेसन टी फेदरिंगम

1
इस उपाय को प्यार करो! हम AJAX आधारित नेविगेशन के लिए URL हैश का उपयोग कर रहे हैं, आईडी को /तार्किक लगता है।
कॉनवेल सेप

3

आपके मूल कोड का एक स्निपेट:

$("#buttons li a").click(function(){
    $("#buttons li a").removeClass('selected');
    $(this).addClass('selected');
    document.location.hash=$(this).attr("id")
});

इसे इसमें बदलें:

$("#buttons li a").click(function(e){
    // need to pass in "e", which is the actual click event
    e.preventDefault();
    // the preventDefault() function ... prevents the default action.
    $("#buttons li a").removeClass('selected');
    $(this).addClass('selected');
    document.location.hash=$(this).attr("id")
});

यह काम नहीं करेगा क्योंकि hashसंपत्ति सेट करने से पेज को वैसे भी स्क्रॉल करना पड़ेगा।
जोर्डनबटकर

3

मैं हाल ही में एक हिंडोला का निर्माण कर रहा था जो window.location.hashराज्य को बनाए रखने के लिए निर्भर करता है और यह खोज की कि क्रोम और वेबकिट ब्राउज़र window.onhashchangeघटना को निकाल दिए जाने पर एक अजीब झटके के साथ (यहां तक ​​कि एक दृश्यमान लक्ष्य को भी) स्क्रॉल करने के लिए मजबूर करेंगे ।

यहां तक ​​कि एक हैंडलर को पंजीकृत करने का प्रयास जो प्रचार बंद कर देता है:

$(window).on("hashchange", function(e) { 
  e.stopPropogation(); 
  e.preventDefault(); 
});

डिफ़ॉल्ट ब्राउज़र व्यवहार को रोकने के लिए कुछ भी नहीं किया। मैंने जो समाधान पाया वह window.history.pushStateअवांछनीय दुष्प्रभावों को ट्रिगर किए बिना हैश को बदलने के लिए उपयोग कर रहा था ।

 $("#buttons li a").click(function(){
    var $self, id, oldUrl;

    $self = $(this);
    id = $self.attr('id');

    $self.siblings().removeClass('selected'); // Don't re-query the DOM!
    $self.addClass('selected');

    if (window.history.pushState) {
      oldUrl = window.location.toString(); 
      // Update the address bar 
      window.history.pushState({}, '', '#' + id);
      // Trigger a custom event which mimics hashchange
      $(window).trigger('my.hashchange', [window.location.toString(), oldUrl]);
    } else {
      // Fallback for the poors browsers which do not have pushState
      window.location.hash = id;
    }

    // prevents the default action of clicking on a link.
    return false;
});

फिर आप सामान्य हैशचेंज घटना और दोनों के लिए सुन सकते हैं my.hashchange:

$(window).on('hashchange my.hashchange', function(e, newUrl, oldUrl){
  // @todo - do something awesome!
});

बेशक my.hashchangeएक उदाहरण घटना का नाम है
अधिकतम

2

ठीक है, यह एक पुराना विषय है, लेकिन मैंने सोचा कि मैं सीएसएस के साथ 'सही' उत्तर के रूप में अच्छी तरह से काम नहीं करूंगा।

यह समाधान मूल रूप से क्लिक इवेंट को पृष्ठ को स्थानांतरित करने से रोकता है ताकि हम पहले स्क्रॉल स्थिति प्राप्त कर सकें। फिर हम मैन्युअल रूप से हैश जोड़ते हैं और ब्राउज़र स्वचालित रूप से एक हैशचेंज घटना को ट्रिगर करता है । हम हैशचेंज इवेंट को कैप्चर करते हैं और सही स्थिति पर वापस स्क्रॉल करते हैं। एक कॉलबैक अलग करता है और आपके कोड को एक स्थान पर आपके हैश हैक करके देरी के कारण रोकता है।

var hashThis = function( $elem, callback ){
    var scrollLocation;
    $( $elem ).on( "click", function( event ){
        event.preventDefault();
        scrollLocation = $( window ).scrollTop();
        window.location.hash = $( event.target ).attr('href').substr(1);
    });
    $( window ).on( "hashchange", function( event ){
        $( window ).scrollTop( scrollLocation );
        if( typeof callback === "function" ){
            callback();
        }
    });
}
hashThis( $( ".myAnchor" ), function(){
    // do something useful!
});

आपको हैशचेंज की जरूरत नहीं है, बस तुरंत वापस स्क्रॉल करें
daniel.gindi

2

Erm मेरे पास कुछ हद तक कच्चा लेकिन निश्चित रूप से काम करने का तरीका है।
बस वर्तमान स्क्रॉल स्थिति को एक अस्थायी चर में संग्रहीत करें और फिर इसे हैश बदलने के बाद रीसेट करें। :)

तो मूल उदाहरण के लिए:

$("#buttons li a").click(function(){
        $("#buttons li a").removeClass('selected');
        $(this).addClass('selected');

        var scrollPos = $(document).scrollTop();
        document.location.hash=$(this).attr("id")
        $(document).scrollTop(scrollPos);
});

इस विधि के साथ समस्या मोबाइल ब्राउज़रों के साथ है आप देख सकते हैं कि स्क्रॉल संशोधित है
टोफंडेल

1

मुझे नहीं लगता कि यह संभव है। जहाँ तक मुझे पता है, केवल एक ब्राउज़र एक परिवर्तित करने के लिए स्क्रॉल नहीं document.location.hashहै अगर हैश पेज के भीतर मौजूद नहीं है।

यह लेख सीधे आपके प्रश्न से संबंधित नहीं है, लेकिन यह विशिष्ट ब्राउज़र व्यवहार बदलने की चर्चा करता हैdocument.location.hash


1

यदि आप हैश पार्सर के साथ हैशचेंज घटना का उपयोग करते हैं, तो आप लिंक पर डिफ़ॉल्ट कार्रवाई को रोक सकते हैं और स्थान बदल सकते हैं। एक तत्व की आईडी संपत्ति के साथ अंतर करने के लिए एक चरित्र को जोड़ना

$('a[href^=#]').on('click', function(e){
    e.preventDefault();
    location.hash = $(this).attr('href')+'/';
});

$(window).on('hashchange', function(){
    var a = /^#?chapter(\d+)-section(\d+)\/?$/i.exec(location.hash);
});

उत्तम! पाँच घंटे के बाद हैश पुनः लोड के साथ समस्या को ठीक करने की कोशिश कर रहा है ...: / यह केवल एक चीज थी जो काम करती थी !! धन्यवाद!!!
इगोर ट्रिन्डेड

1

इसे यहां जोड़ना क्योंकि अधिक प्रासंगिक प्रश्नों को सभी को यहां इंगित करने वाले डुप्लिकेट के रूप में चिह्नित किया गया है ...

मेरी स्थिति सरल है:

  • उपयोगकर्ता लिंक पर क्लिक करता है ( a[href='#something'])
  • क्लिक हैंडलर करता है: e.preventDefault()
  • smoothscroll समारोह: $("html,body").stop(true,true).animate({ "scrollTop": linkoffset.top }, scrollspeed, "swing" );
  • फिर window.location = link;

इस तरह, स्क्रॉल तब होता है, और जब स्थान अपडेट किया जाता है तो कोई छलांग नहीं होती है।


0

ऐसा करने का दूसरा तरीका यह है कि व्यूपोर्ट के शीर्ष पर छिपी एक डिव को जोड़ना है। इस div को url में जोड़े जाने से पहले hash की id असाइन की जाती है .... तो फिर आपको स्क्रॉल नहीं मिलता है।


0

यहाँ इतिहास-सक्षम टैब के लिए मेरा समाधान है:

    var tabContainer = $(".tabs"),
        tabsContent = tabContainer.find(".tabsection").hide(),
        tabNav = $(".tab-nav"), tabs = tabNav.find("a").on("click", function (e) {
                e.preventDefault();
                var href = this.href.split("#")[1]; //mydiv
                var target = "#" + href; //#myDiv
                tabs.each(function() {
                    $(this)[0].className = ""; //reset class names
                });
                tabsContent.hide();
                $(this).addClass("active");
                var $target = $(target).show();
                if ($target.length === 0) {
                    console.log("Could not find associated tab content for " + target);
                } 
                $target.removeAttr("id");
                // TODO: You could add smooth scroll to element
                document.location.hash = target;
                $target.attr("id", href);
                return false;
            });

और अंतिम चयनित टैब दिखाने के लिए:

var currentHashURL = document.location.hash;
        if (currentHashURL != "") { //a tab was set in hash earlier
            // show selected
            $(currentHashURL).show();
        }
        else { //default to show first tab
            tabsContent.first().show();
        }
        // Now set the tab to active
        tabs.filter("[href*='" + currentHashURL + "']").addClass("active");

कॉल *=पर ध्यान दें filter। यह एक jQuery की विशिष्ट चीज़ है, और इसके बिना, आपका इतिहास-सक्षम टैब विफल हो जाएगा।


0

यह समाधान वास्तविक स्क्रॉलटॉप पर एक div बनाता है और इसे हैश बदलने के बाद निकालता है:

$('#menu a').on('click',function(){
    //your anchor event here
    var href = $(this).attr('href');
    window.location.hash = href;
    if(window.location.hash == href)return false;           
    var $jumpTo = $('body').find(href);
    $('body').append(
        $('<div>')
            .attr('id',$jumpTo.attr('id'))
            .addClass('fakeDivForHash')
            .data('realElementForHash',$jumpTo.removeAttr('id'))
            .css({'position':'absolute','top':$(window).scrollTop()})
    );
    window.location.hash = href;    
});
$(window).on('hashchange', function(){
    var $fakeDiv = $('.fakeDivForHash');
    if(!$fakeDiv.length)return true;
    $fakeDiv.data('realElementForHash').attr('id',$fakeDiv.attr('id'));
    $fakeDiv.remove();
});

पेज लोड होने पर वैकल्पिक, ट्रिगर एंकर घटना:

$('#menu a[href='+window.location.hash+']').click();

0

मेरे पास एक सरल विधि है जो मेरे लिए काम करती है। असल में, याद रखें कि वास्तव में HTML में हैश क्या है। यह नाम टैग के लिए एक लंगर लिंक है। इसलिए यह स्क्रॉल करता है ... ब्राउज़र एक एंकर लिंक पर स्क्रॉल करने का प्रयास कर रहा है। तो, यह एक दे दो!

  1. BODY टैग के नीचे दाईं ओर अपना संस्करण डालें:
 <a name="home"> </a> <a name="firstsection"> </a> <a name="secondsection"> </a> <a name="thirdsection"> </a>
  1. आईडी के बजाय कक्षाओं के साथ अपने अनुभाग विभाग का नाम दें।

  2. अपने प्रोसेसिंग कोड में, हैश मार्क को हटा दें और एक डॉट के साथ बदलें:

    var trimPanel = loadhash.substring (1); // हैश खोना

    var dotSelect = '।' + ट्राइपैननेल; // हैश को डॉट से बदलें

    $ (DotSelect) .addClass ( "activepanel") शो ()।; // हैश से जुड़े div दिखाओ।

अंत में, element.preventDefault या वापसी को हटा दें: गलत और नौसेना को होने दें। खिड़की सबसे ऊपर रहेगी, हैश को एड्रेस बार यूआरएल से जोड़ा जाएगा, और सही पैनल खुलेगा।


0

मुझे लगता है कि आपको हैशचेंज से पहले स्क्रॉल को अपनी स्थिति में रीसेट करना होगा।

$(function(){
    //This emulates a click on the correct button on page load
    if(document.location.hash) {
        $("#buttons li a").removeClass('selected');
        s=$(document.location.hash).addClass('selected').attr("href").replace("javascript:","");
        eval(s);
    }

    //Click a button to change the hash
    $("#buttons li a").click(function() {
            var scrollLocation = $(window).scrollTop();
            $("#buttons li a").removeClass('selected');
            $(this).addClass('selected');
            document.location.hash = $(this).attr("id");
            $(window).scrollTop( scrollLocation );
    });
});

0

यदि आपके पृष्ठ पर आप एक एंकर पॉइंट के रूप में आईडी का उपयोग करते हैं, और आपके पास ऐसे परिदृश्य हैं जहां आप उपयोगकर्ताओं को url के अंत में #something को जोड़ना चाहते हैं और अपने स्वयं के अनुकूलित एनिमेटेड का उपयोग करके पेज को उस # अनुभाग में स्क्रॉल करें जावास्क्रिप्ट फ़ंक्शन, हैशचेंज इवेंट श्रोता ऐसा नहीं कर पाएंगे।

यदि आप हैशचेंज घटना के तुरंत बाद डिबगर लगाते हैं, उदाहरण के लिए, कुछ इस तरह (ठीक है, मैं jquery का उपयोग करता हूं, लेकिन आपको बिंदु मिलता है):

$(window).on('hashchange', function(){debugger});

आप देखेंगे कि जैसे ही आप अपना url बदलते हैं और एंटर बटन दबाते हैं, पेज तुरंत संबंधित सेक्शन में रुक जाता है, उसके बाद ही, आपका खुद का परिभाषित स्क्रॉल फंक्शन ट्रिगर होगा, और यह उस सेक्शन को स्क्रॉल करता है, जो दिखता है बहुत बुरा।

मेरा सुझाव है:

  1. जिस अनुभाग को आप स्क्रॉल करना चाहते हैं, उसके लिए अपने एंकर बिंदु के रूप में आईडी का उपयोग न करें।

  2. यदि आप आईडी का उपयोग करते हैं, तो जैसे मैं करता हूं। इसके बजाय 'popstate' ईवेंट श्रोता का उपयोग करें, यह स्वचालित रूप से उस अनुभाग पर स्क्रॉल नहीं करेगा जिसे आप url में जोड़ते हैं, इसके बजाय, आप popstate इवेंट के अंदर अपने स्वयं के परिभाषित फ़ंक्शन को कॉल कर सकते हैं।

    $(window).on('popstate', function(){myscrollfunction()});

अंत में आपको अपने स्वयं के परिभाषित स्क्रॉल फ़ंक्शन में थोड़ी सी चाल करने की आवश्यकता है:

    let hash = window.location.hash.replace(/^#/, '');
    let node = $('#' + hash);
    if (node.length) {
        node.attr('id', '');
    }
    if (node.length) {
        node.attr('id', hash);
    }

अपने टैग पर आईडी हटाएं और इसे रीसेट करें।

यह काम कर जाना चाहिए।


-5

दस्तावेज़ तैयार होने पर ही इस कोड को jQuery में जोड़ें

रेफरी: http://css-tricks.com/snippets/jquery/smooth-scrolling/

$(function() {
  $('a[href*=#]:not([href=#])').click(function() {
    if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
      var target = $(this.hash);
      target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
      if (target.length) {
        $('html,body').animate({
          scrollTop: target.offset().top
        }, 1000);
        return false;
      }
    }
  });
});
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.