इवेंट जब window.location.href बदलता है


88

मैं एक साइट के लिए एक Greasemonkey स्क्रिप्ट लिख रहा हूँ जो कुछ बिंदु पर संशोधित करता है location.href

मैं (के माध्यम से घटना कैसे प्राप्त कर सकते हैं window.addEventListenerया कुछ इसी तरह) जब window.location.hrefएक पृष्ठ पर परिवर्तन? मुझे नए / संशोधित url की ओर इशारा करते हुए दस्तावेज़ के DOM तक पहुंचने की भी आवश्यकता है।

मैंने अन्य समाधान देखे हैं जिनमें टाइमआउट और मतदान शामिल हैं, लेकिन मैं यदि संभव हो तो इससे बचना चाहूंगा।


जवाबों:


90

आबाद घटना :

सक्रिय इतिहास प्रविष्टि में परिवर्तन होने पर पॉपस्टैट घटना को निकाल दिया जाता है। [...] पॉपस्टैट ईवेंट केवल एक ब्राउज़र क्रिया करके ट्रिगर की जाती है जैसे बैक बटन पर एक क्लिक (या जावास्क्रिप्ट में history.back () कॉलिंग)

इसलिए, popstateईवेंट को सुनना और popstateजब कोई ईवेंट भेजा जाता है, तो परिवर्तन history.pushState()पर कार्रवाई करने के लिए पर्याप्त होना चाहिए href:

window.addEventListener('popstate', listener);

const pushUrl = (href) => {
  history.pushState({}, '', href);
  window.dispatchEvent(new Event('popstate'));
};

2
लेकिन क्या सामग्री लोड होने से पहले पॉपस्टैट में आग लग जाएगी?
user2782001

4
अनुपयोगी होने पर कोड के टुकड़े पर कोई नियंत्रण नहीं है किpushState
नाथन गॉई

2
यह हमेशा काम नहीं करता है, यह एक पॉपस्टेट घटना पर आधारित होता है जिसे निकाल दिया जाता है। उदाहरण के लिए YouTube के भीतर नेविगेट करने से यह ट्रिगर नहीं होगा, केवल तभी जब आप इतिहास में आगे या पीछे दबाते हैं
ट्राइस्पेस

57

मैं अपने विस्तार में इस स्क्रिप्ट का उपयोग करता हूं "ग्रैब एनी मीडिया" और ठीक काम ( जैसे youtube केस )

var oldHref = document.location.href;

window.onload = function() {

    var
         bodyList = document.querySelector("body")

        ,observer = new MutationObserver(function(mutations) {

            mutations.forEach(function(mutation) {

                if (oldHref != document.location.href) {

                    oldHref = document.location.href;

                    /* Changed ! your code here */

                }

            });

        });

    var config = {
        childList: true,
        subtree: true
    };

    observer.observe(bodyList, config);

};

किसी तरह, मुझे यह तरीका पसंद है ... थोड़ा RxJs-ish :) लगता है
गुंट्रम

एकमात्र समाधान जो youtube के लिए काम कर सकता था: [रिपोर्ट केवल] ' youtube.com/sw.js ' से एक कार्यकर्ता बनाने से इनकार कर दिया क्योंकि यह निम्नलिखित सामग्री सुरक्षा नीति के निर्देश का उल्लंघन करता है: "कार्यकर्ता-src 'कोई नहीं"।
साइमन मेउल

MutationObserver

1
मेरे उपयोग के मामले के लिए बिना किसी परेशानी के बॉक्स से बाहर काम किया, भगवान भला करे! यह कष्टप्रद है कि इसके लिए अभी तक कोई देशी घटना नहीं है (एक दिन मेरे लिए काम नहीं किया गया) लेकिन एक दिन! मैं window.addEventListener("load", () => {})window.onload के बजाय उपयोग करूंगा हालांकि :)
संचित बत्रा

यह काम करता है, इतिहास का पता लगाता है। विस्तार संदर्भ में भी
PushState

29

आप मतदान से बच नहीं सकते, href परिवर्तन के लिए कोई घटना नहीं है।

यदि आप ओवरबोर्ड नहीं जाते हैं तो अंतराल का उपयोग करना काफी हल्का है। यदि आप उस बारे में चिंतित हैं, तो हर 50ms पर href की जाँच करना या प्रदर्शन पर कोई महत्वपूर्ण प्रभाव नहीं पड़ेगा।


3
@AlexanderMills: सौभाग्य से वहाँ के इन नए समाधान कर रहे हैं popstateऔर hashchange
सर्व-इंक

1
यह सच नहीं है।
inf3rno

@ MartinZvarík 2010 में भी नए दस्तावेज़ को लोड करने के लिए अनलोड इवेंट प्लस माइक्रो या मैक्रो कार्य का उपयोग करना संभव था।
inf3rno

3
दुर्भाग्य से यह उत्तर अभी भी 2020 में सही है। केवल तब आग लगती है जब उपयोगकर्ता आगे / पीछे बटन का उपयोग करता है और हैशचेंज केवल हैश परिवर्तन के लिए आग लगाता है। जब तक आपके पास उस कोड पर नियंत्रण नहीं है जो स्थान बदलने का कारण बन रहा है, आपको 🤷 have have
Rico Kahler

14

एक डिफ़ॉल्ट onhashchangeघटना है जिसका आप उपयोग कर सकते हैं।

यहाँ पर प्रलेखित

और इस तरह इस्तेमाल किया जा सकता है:

function locationHashChanged( e ) {
    console.log( location.hash );
    console.log( e.oldURL, e.newURL );
    if ( location.hash === "#pageX" ) {
        pageX();
    }
}

window.onhashchange = locationHashChanged;

यदि ब्राउज़र समर्थन नहीं करता है oldURLऔर newURLआप इसे इस तरह बांध सकते हैं:

//let this snippet run before your hashChange event binding code
if( !window.HashChangeEvent )( function() {
    let lastURL = document.URL;
    window.addEventListener( "hashchange", function( event ) {
        Object.defineProperty( event, "oldURL", { enumerable: true, configurable: true, value: lastURL } );
        Object.defineProperty( event, "newURL", { enumerable: true, configurable: true, value: document.URL } );
        lastURL = document.URL;
    } );
} () );

8
Hashchange ईवेंट केवल तभी भेजे जाते हैं जब आपके URL में '#' प्रतीक के साथ शुरू होने वाला हिस्सा होता है, जिसे आमतौर पर एंकर लिंक के लिए उपयोग किया जाता है। अन्यथा यह आग नहीं होगा।
फ्रेड्रिक_माक्रोबॉन्ड

1
window.addEventListener ("hashchange", funcRef, false);
बिशॉय हन्ना

7

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

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
    <HTML>
    <HEAD>
    <TITLE></TITLE>
    <META NAME="Generator" CONTENT="TextPad 4.6">
    <META NAME="Author" CONTENT="?">
    <META NAME="Keywords" CONTENT="?">
    <META NAME="Description" CONTENT="?">
    </HEAD>

         <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript"></script>
            <script type="text/javascript">
            $(document).ready(function(){
                $(window).unload(
                        function(event) {
                            alert("navigating");
                        }
                );
                $("#theButton").click(
                    function(event){
                        alert("Starting navigation");
                        window.location.href = "http://www.bbc.co.uk";
                    }
                );

            });
            </script>


    <BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#FF0000" VLINK="#800000" ALINK="#FF00FF" BACKGROUND="?">

        <button id="theButton">Click to navigate</button>

        <a href="http://www.google.co.uk"> Google</a>
    </BODY>
    </HTML>

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


मुझे यकीन नहीं है कि यह काम करेगा क्योंकि अक्सर हैश परिवर्तन में पेज लोड नहीं होता है।
samandmoore

मुझे नए DOM तक पहुँच की आवश्यकता है, मैंने यह स्पष्ट करने के लिए प्रश्न को अद्यतन किया।
जोहान डाहलिन

ठीक - hashस्थिति पर विचार नहीं किया - उस बारे में सोचेंगे। के रूप में नए डोम का उपयोग करने में सक्षम होने के बाद, तो आप भाग्य से बाहर हैं (जहाँ तक किसी ईवेंट हैंडलर से इसे एक्सेस करने का संबंध है) क्योंकि नई डीओएम लोड होने से पहले ईवेंट आग लग जाएगा। आप नए पृष्ठ के ऑन-लोड ईवेंट में तर्क को शामिल करने में सक्षम हो सकते हैं, लेकिन आपके पास उसी मुद्दे के संबंध में पहचान हो सकती है कि आपको उस पृष्ठ के प्रत्येक लोड के लिए तर्क को पूरा करने की आवश्यकता है या नहीं। क्या आप पृष्ठ प्रवाह सहित, जो आप प्राप्त करने की कोशिश कर रहे हैं, उसके बारे में कुछ और विवरण प्रदान कर सकते हैं?
बेलुगोबोब

मैंने अभी onbeforeunload इवेंट हैंडलर के अंदर location.href एक्सेस करने की कोशिश की, और यह मूल url को दिखाता है, न कि लक्ष्य url को।
CMCDragonkai

इससे पहले कि लोड करना पृष्ठ को अनलोड करना रद्द कर सकता है, इसलिए यदि आप नेविगेशन रद्द नहीं करना चाहते हैं, तो अनलोड घटना बेहतर है।
inf3rno

7

Jquery के माध्यम से , बस कोशिश करें

$(window).on('beforeunload', function () {
    //your code goes here on location change 
});

जावास्क्रिप्ट का उपयोग करके :

window.addEventListener("beforeunload", function (event) {
   //your code goes here on location change 
});

दस्तावेज़ देखें: https://developer.mozilla.org/en-US/docs/Web/Events/beforeunload


2

वैसे बदलने के 2 तरीके है location.href। या तो आप लिख सकते हैंlocation.href = "y.html" , जो पृष्ठ को फिर से लोड करता है या इतिहास एपीआई का उपयोग कर सकता है जो पृष्ठ को फिर से लोड नहीं करता है। मैंने हाल ही में पहला प्रयोग किया।

यदि आप एक चाइल्ड विंडो खोलते हैं और पेरेंट विंडो से चाइल्ड पेज का लोड कैप्चर करते हैं, तो अलग-अलग ब्राउजर बहुत अलग तरह से व्यवहार करते हैं। केवल एक चीज जो सामान्य है, वह यह है कि वे पुराने दस्तावेज़ को हटाते हैं और एक नया जोड़ते हैं, इसलिए उदाहरण के लिए पुराने दस्तावेज़ में रीडिस्टेटचेंज या लोड इवेंट हैंडलर्स को जोड़ने से कोई प्रभाव नहीं पड़ता है। अधिकांश ब्राउज़र विंडो ऑब्जेक्ट से ईवेंट हैंडलर को भी हटा देते हैं, एकमात्र अपवाद फ़ायरफ़ॉक्स है। क्रोम में कर्मा धावक और फ़ायरफ़ॉक्स में आप लोड करने के लिए तैयार डॉक्यूमेंट में नए डॉक्यूमेंट को कैप्चर कर सकते हैंunload + next tick। इसलिए आप उदाहरण के लिए एक लोड इवेंट हैंडलर या एक रीडायस्टेकचेंज ईवेंट हैंडलर जोड़ सकते हैं या बस लॉग इन कर सकते हैं कि ब्राउज़र एक नया यूआरआई वाला पेज लोड कर रहा है। Chrome में मैन्युअल परीक्षण (शायद GreaseMonkey भी) और ओपेरा में, PhantomJS, IE10, IE11 के साथ आप लोडिंग राज्य में नए दस्तावेज़ पर कब्जा नहीं कर सकते। उन ब्राउज़रों में unload + next tickकॉलबैक पृष्ठ की आग की घटना की तुलना में कुछ सौ एमएसईसी बाद में होता है। देरी आमतौर पर 100 से 300 मिसे होती है, लेकिन ओपेरा सिमटाइम अगले टिक के लिए 750 मिसे देरी करता है, जो डरावना है। इसलिए यदि आप सभी ब्राउज़रों में लगातार परिणाम चाहते हैं, तो आप वही करें जो आप लोड इवेंट के बाद करना चाहते हैं, लेकिन इस बात की कोई गारंटी नहीं है कि इससे पहले स्थान को ओवरराइड नहीं किया जाएगा।

var uuid = "win." + Math.random();
var timeOrigin = new Date();
var win = window.open("about:blank", uuid, "menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes");


var callBacks = [];
var uglyHax = function (){
    var done = function (){
        uglyHax();
        callBacks.forEach(function (cb){
            cb();
        });
    };
    win.addEventListener("unload", function unloadListener(){
        win.removeEventListener("unload", unloadListener); // Firefox remembers, other browsers don't
        setTimeout(function (){
            // IE10, IE11, Opera, PhantomJS, Chrome has a complete new document at this point
            // Chrome on Karma, Firefox has a loading new document at this point
            win.document.readyState; // IE10 and IE11 sometimes fails if I don't access it twice, idk. how or why
            if (win.document.readyState === "complete")
                done();
            else
                win.addEventListener("load", function (){
                    setTimeout(done, 0);
                });
        }, 0);
    });
};
uglyHax();


callBacks.push(function (){
    console.log("cb", win.location.href, win.document.readyState);
    if (win.location.href !== "http://localhost:4444/y.html")
        win.location.href = "http://localhost:4444/y.html";
    else
        console.log("done");
});
win.location.href = "http://localhost:4444/x.html";

यदि आप अपनी स्क्रिप्ट केवल फ़ायरफ़ॉक्स में चलाते हैं, तो आप एक सरलीकृत संस्करण का उपयोग कर सकते हैं और दस्तावेज़ को लोडिंग स्थिति में कैप्चर कर सकते हैं, इसलिए उदाहरण के लिए, लोड किए गए पृष्ठ पर कोई स्क्रिप्ट URI परिवर्तन लॉग करने से पहले नेविगेट नहीं कर सकता:

var uuid = "win." + Math.random();
var timeOrigin = new Date();
var win = window.open("about:blank", uuid, "menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes");


var callBacks = [];
win.addEventListener("unload", function unloadListener(){
    setTimeout(function (){
        callBacks.forEach(function (cb){
            cb();
        });
    }, 0);
});


callBacks.push(function (){
    console.log("cb", win.location.href, win.document.readyState);
    // be aware that the page is in loading readyState, 
    // so if you rewrite the location here, the actual page will be never loaded, just the new one
    if (win.location.href !== "http://localhost:4444/y.html")
        win.location.href = "http://localhost:4444/y.html";
    else
        console.log("done");
});
win.location.href = "http://localhost:4444/x.html";

यदि हम एकल पृष्ठ अनुप्रयोगों के बारे में बात कर रहे हैं जो यूआरआई के हैश भाग को बदलते हैं, या इतिहास एपीआई का उपयोग करते हैं, तो आप क्रमशः और विंडो hashchangeकी popstateघटनाओं का उपयोग कर सकते हैं। यदि आप इतिहास में आगे बढ़ते हैं और जब तक आप एक ही पृष्ठ पर नहीं रहते तब भी वे कब्जा कर सकते हैं। दस्तावेज़ उन लोगों द्वारा नहीं बदलता है और पृष्ठ वास्तव में पुनः लोड नहीं किया जाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.