Why doesn't window.onhashchange work in tampermonkey?

2 min read 05-10-2024
Why doesn't window.onhashchange work in tampermonkey?


Why window.onhashchange Doesn't Work in Tampermonkey

Tampermonkey, a popular browser extension for user scripts, can sometimes present unexpected behavior when dealing with JavaScript's window.onhashchange event. This event is typically used to trigger actions when the URL's hash portion (the part after the # symbol) changes, but it doesn't function as expected within Tampermonkey scripts.

The Problem:

Imagine you have a Tampermonkey script that aims to listen for hash changes on a website and perform actions based on the new hash value. You might use the window.onhashchange event to accomplish this. However, you'll find that the script fails to detect hash changes.

The Scenario:

Let's say you have the following Tampermonkey script:

// ==UserScript==
// @name     Hash Change Listener
// @namespace  http://tampermonkey.net/
// @version  1.0
// @description  Tries to listen for hash changes
// @match    *://*/*
// @grant    none
// ==/UserScript==

window.onhashchange = function() {
  console.log("Hash changed!");
  console.log("New hash:", window.location.hash);
}

You expect this script to log "Hash changed!" and the new hash value whenever the URL's hash changes. However, the script remains silent, even when the hash is modified.

Why This Happens:

The reason lies in how Tampermonkey executes scripts. Tampermonkey runs user scripts in a separate isolated environment to maintain security and prevent conflicts with the website's JavaScript. This isolation prevents direct access to certain browser events, including window.onhashchange.

The Solution:

To address this, you need to find an alternative approach to detect hash changes within Tampermonkey:

  1. Use a Polling Mechanism: Create a function that periodically checks the current hash value and compares it to the previous value. If they differ, it indicates a hash change.

    // ...
    let previousHash = window.location.hash;
    
    function checkHashChange() {
        const currentHash = window.location.hash;
        if (currentHash !== previousHash) {
            console.log("Hash changed!");
            console.log("New hash:", currentHash);
            previousHash = currentHash;
        }
    }
    
    setInterval(checkHashChange, 100); // Check every 100 milliseconds
    
  2. Utilize MutationObserver: Observe the changes to the window.location object, specifically the hash property.

    // ...
    const observer = new MutationObserver(mutations => {
        mutations.forEach(mutation => {
            if (mutation.attributeName === 'hash') {
                console.log("Hash changed!");
                console.log("New hash:", window.location.hash);
            }
        });
    });
    
    observer.observe(window.location, { attributes: true, attributeFilter: ['hash'] });
    

Additional Tips:

  • Optimize Polling: Adjust the interval for setInterval based on the expected frequency of hash changes to balance performance and responsiveness.
  • Handle Navigation: Consider implementing checks to ensure that the hash change event wasn't triggered due to a page navigation.

In Conclusion:

While window.onhashchange doesn't work directly in Tampermonkey scripts, you can effectively achieve the same functionality using alternative techniques like polling or MutationObserver. By understanding these limitations and adopting suitable solutions, you can successfully work with hash changes within your Tampermonkey scripts.