在Chrome插件中访问原始网页中的变量

转自:http://www.keakon.net/2011/11/02/%E5%9C%A8Chrome%E6%8F%92%E4%BB%B6%E4%B8%AD%E8%AE%BF%E9%97%AE%E5%8E%9F%E5%A7%8B%E7%BD%91%E9%A1%B5%E4%B8%AD%E7%9A%84%E5%8F%98%E9%87%8F

今天凌晨在写Reader Sharer插件时遇到个问题。

Google Reader这个网页有_COMMAND_TOKEN这个全局变量,我需要使用它,但Chrome插件的 Content Scripts 的执行环境和原始网页是不一样的,导致没法用window._COMMAND_TOKEN来直接获取。

如果是在Firefox中,我可以使用unsafeWindow._COMMAND_TOKEN来直接获取;很早以前的Chrome插件也是和原始网页共享执行环境的,可惜美好的日子一去不复返了。
幸运的是我找到 “How can I mimic Greasemonkey/Firefox's unsafeWindow functionality in Chrome?” 这个问题,得到了3种解决办法。

考虑到Google Reader的网页太复杂,这里就以Google首页来举例了。打开网页后,右键打开审查元素,然后在控制台输入fp,就会看到一个字符串,这就是原始网页的一个全局变量。

现在我要获取它,就可以创建一个script元素,append到head。而这个script元素的执行环境是原始网页的,可以自由使用fp这个变量。
不过fp取出来后也没法直接传递回content script。好在文档里说DOM是共用的,所以可以在这个script里,把值设置为某个元素的属性或innerText,再在content script里获取就行了:
setTimeout(function() {
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.innerHTML = "document.body.setAttribute('data-fp', fp);";
    document.head.appendChild(script);
    document.head.removeChild(script);

    console.log(document.body.getAttribute('data-fp'));
}, 1000);
这里延迟的原因是原始网页加载完时,还需要等一会才会创建fp变量。

另一种办法就是使用location.href,它是用来跳转网页的,但是也可以用来执行JavaScript,并且执行环境也是原始网页:
setTimeout(function() {
    location.href = "javascript:document.body.setAttribute('data-fp', fp);";
    setTimeout(function() {
        console.log(document.body.getAttribute('data-fp'));
    }, 0);
}, 1000);
这里嵌套使用了setTimeout,原因是跳转是一个事件,并不会打断当前脚本的执行(而添加script元素会立刻执行),因此需要让后面的语句等待事件处理完毕。

不过前面所说的方法都必须先保存,再取出,能这样做的只有字符串等简单类型,对函数则无能为力了。
实际上还有更方便的方法,那就是在DOM上绑定一个事件,而事件的处理函数则返回window变量,再在程序中触发这个事件,就能获得执行环境的window变量了。幸运的是,这个执行环境仍然是原始网页的:
setTimeout(function() {
    var div = document.createElement('div');
    div.setAttribute('onclick', 'return window;');
    var unsafeWindow = div.onclick();
    console.log(unsafeWindow.fp);
}, 1000);

你可能感兴趣的:(Javascript)