Chrome扩展中能否监听主JS变量?偏好使用Proxy实现
Hey there! The core issue you're hitting is Chrome's isolated worlds feature: content scripts run in their own separate context, so they can't directly access or modify the page's global variables (like your hp). That's why your setInterval loop feels like a hack—but we can fix this cleanly with Proxy, no polling required.
Here's a step-by-step solution that lets you listen to variable changes in real time:
1. Understand the Workflow
We need two parts to make this work:
- A script injected into the page's main context (not the content script's isolated world) to set up the Proxy and watch the variable.
- Communication between this injected script and your content script using custom browser events, since they can't share scope directly.
2. Implement the Proxy & Event Communication
Step 1: Inject the Proxy Script into the Page
First, we'll inject a script into the page's main world to wrap your hp variable in a Proxy. This Proxy will intercept any changes to the variable and fire a custom event that your content script can listen to.
Add this to your content script:
// Content Script: Inject the Proxy setup into the page's main context function injectProxyScript() { const script = document.createElement('script'); script.textContent = ` (function() { // Wait for the global 'hp' variable to exist (in case it loads later) function setupHPProxy() { if (typeof window.hp === 'undefined') { setTimeout(setupHPProxy, 100); return; } // Proxy can only handle objects—wrap primitive values (numbers/strings) in an object const hpTarget = typeof window.hp === 'object' ? window.hp : { value: window.hp }; // Replace the global 'hp' with our Proxy window.hp = new Proxy(hpTarget, { set: function(target, prop, newValue) { const oldValue = target[prop]; // Update the actual value target[prop] = newValue; // Only fire an event if the value actually changed if (oldValue !== newValue) { window.dispatchEvent(new CustomEvent('hpUpdated', { detail: { newValue: typeof hpTarget.value !== 'undefined' ? hpTarget.value : newValue, property: prop } })); } return true; }, // Optional: Intercept 'get' calls if you need to track reads get: function(target, prop) { return target[prop]; } }); // Send the initial value to the content script window.dispatchEvent(new CustomEvent('hpUpdated', { detail: { newValue: typeof hpTarget.value !== 'undefined' ? hpTarget.value : window.hp } })); } setupHPProxy(); })(); `; document.documentElement.appendChild(script); script.remove(); // Clean up the injected script tag } // Run the injection when the content script loads injectProxyScript();
Step 2: Listen for Changes in the Content Script
Now, in your content script, add a listener for the custom hpUpdated event to get real-time updates:
// Content Script: Listen for updates from the page's Proxy window.addEventListener('hpUpdated', (event) => { const { newValue } = event.detail; // Do whatever you need with the updated HP value console.log('HP just changed to:', newValue); // Your logic here (e.g., update UI, send to background script) });
3. Key Notes
- Primitive vs. Object Variables: Proxy can only wrap objects, so we automatically wrap primitive values (like numbers) in a
{ value: ... }object. The event will still pass the raw value to your content script, so you don't have to handle the wrapper there. - Timing: The script waits for
window.hpto exist before setting up the Proxy, which handles cases where the variable is initialized after the page loads. - No Polling: This setup triggers updates only when the variable actually changes—no more setInterval loops wasting resources.
Why This Works
- The injected script runs in the page's main context, so it has full access to global variables.
- The Proxy intercepts all writes to
hpand fires a custom event. - Your content script listens for this event, which crosses the isolated world boundary safely.
内容的提问来源于stack exchange,提问作者Tree Nguyen

