簡體   English   中英

如何在選項卡的主窗口對象上定義屬性?

[英]How can I define a property on the tab's main window object?

我正在嘗試使用setter中的代碼從內容腳本中定義window對象上的屬性jQuery 這樣,當定義實際的jQuery對象時,我可以立即使用它。 不過,我似乎無法做到正確。

目標網站是Outlook.com。 這是Outlook的網絡郵件版本。

我試圖直接將代碼放在內容腳本中,但即使我在清單的content_scripts部分中放入"all_frames": true (因此代碼被注入每個幀),它也無法正常工作。

function afterInit(){
  var _jQuery;
  console.log('This gets logged');
  Object.defineProperty(window, 'jQuery', {
    get: function() { return _jQuery; },
    set: function(newValue) {
      _jQuery = $ = newValue;

      console.log('This is never logged!');

      $(document.body).append($('<span>I want to use jQuery here</span>'));
    }
  });
}
afterInit();

我驗證了window.jQuery之后被實際的jQuery函數/對象正確定義,但我的setter代碼從未執行過。
我也嘗試了消息傳遞:我將一個帶有代碼的消息作為字符串發送到后台腳本,並使用executeScript在正確的選項卡上執行它,但這也不起作用。

chrome.runtime.sendMessage(
    {action:'jQueryPreInit', value: '('+afterInit.toString()+')();'});

在我的后台腳本中:

chrome.runtime.onMessage.addListener(function(message, sender, callback) {
  switch (message.action){
    case "jQueryPreInit": chrome.tabs.executeScript(sender.tab.id, {code: message.value});
  }
});

如果我在executeScript代碼中添加了除Object.defineProperty代碼以外的其他代碼,那么工作正常。 我只有定義屬性的問題。

(報價來自評論)

我想使用頁面本身提供的jQuery。 我可以嘗試插入與Outlook相同的jQuery文件,並希望它從緩存中加載,但我寧願保持我的擴展盡可能干凈,並使用已有的。

您嘗試優化擴展程序是不可行/不推薦的。

首先,由於內容腳本和網頁代碼之間的隔離 ,您無法使用頁面代碼 你無法獲得對頁面自己的jQuery / $的引用。

但是,讓我們暫時假設你可以。 然后該站點將jQuery更新為另一個版本,重命名jQuery對象或完全停止使用它,這是您無法控制的。 結果:您的擴展程序已損壞。 部分地,這首先是隔離背后的基本原理。

作為上下文隔離的結果,您可以保證您的jQuery副本與站點上運行的任何內容之間不存在沖突。 因此,您無需擔心:使用您的副本,並使用標准$來訪問它。

將一個<100 KB的文件與您的擴展程序捆綁在一起作為一次性下載,以確保代碼在100%的時間內可用,並且在最壞的情況下磁盤訪問延遲並不會使它變得不那么“干凈”,恰恰相反。 這是一種常見的做法,並在文檔中得到了體現


查看您的實際代碼,它在內容腳本上下文中執行(無論是通過manifest還是executeScript ),而不是在頁面上下文中。 因此,無論頁面是什么,都不會在那里定義$

我驗證了window.jQuery之后被實際的jQuery函數/對象正確定義[...]

我假設你試圖在控制台中執行window.jQuery ; 默認情況下, 它在頁面上下文執行,而不是在內容腳本上下文中執行 (因此,不反映內容腳本上下文的狀態而不是調用getter / setter )。 如果要測試內容腳本,則需要在控制台top的上下文下拉列表中將top更改為擴展的上下文。


然而,所有這一切,

完成所有操作后,我想使用jQuery的ajaxSuccess函數在每次在閱讀窗格中打開電子郵件時執行代碼。

我們遇到了一個問題。 由於內容腳本代碼和網頁代碼是隔離的,因此您的代碼永遠不會知道在頁面副本中執行的AJAX(無論如何都不是通過ajaxSuccess )。

可能的行動方針:

  1. 依靠其他方法來檢測您想要的事件。 也許監控DOM
  2. 將一些代碼注入頁面本身 ; 唯一的方法是從內容腳本中將<script>標記注入頁面。 在那里,您可以訪問頁面的jQuery副本,附加您的監聽器並在發生某些事情時向您的內容腳本發送消息
  3. 依靠后台頁面來檢測webRequest API所需的活動。 這可能會攔截AJAX調用,但不會給你回復內容。

最后注意:這可能不像AJAX調用那么簡單; 也許該頁面維護一個WebSocket連接以獲得實時推送更新。 利用這個比較棘手。

感謝Xan,我發現只有兩種方法可以做到這一點。

第一種方法是向包含適當代碼的DOM添加<script>元素。 這是一個非常廣泛的StackOverflow答案,如何做到這一點: https//stackoverflow.com/a/9517879/125938

第二個是使用Javascript偽URL和window.location對象。 通過為window.location分配包含Javascript的bookmarklet樣式的URL,您還可以繞過某些安全措施。 在內容腳本中,放入:

location = 'javascript:(' + (function(){
  var _jQuery;
  Object.defineProperty(window, 'jQuery', {
    get: function() { return _jQuery; },
    set: function(newValue) {
      _jQuery = $ = newValue;

      console.log('totally logged!');

      $('<span>jQuery stuff here</span>');

    }
  });
}).toString().replace(/\n/g, ' ')+')();';

我/你最初未能定義它的原因是因為我們使用的兩種代碼注入方法都導致我們的代碼被沙盒化為孤立的世界: https//developer.chrome.com/extensions/content_scripts#execution-environment 意思是,它們共享頁面的DOM並可以通過它進行通信,但是它們不能直接訪問彼此的window對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM