開發chrome插件時遇到需要獲取原始網頁中的一個js變量的值問題。由於content.js和原始網頁的作用域環境不同,無法直接獲取變量的值,提示undefined。谷歌找到大神提供的辦法。綜合起來記錄如下:
考慮到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);