2015-09-25 17 views
5

tôi post đoạn code dưới đây:tin nhắn giữa kịch bản nội dung và trang nền trong một phần mở rộng chrome không hoạt động vì nó được coi là

manifest.json

{ 
    "manifest_version": 2, 

    "name": "Demo", 
    "description": "all_frames test", 
    "version": "1.0", 

    "background": { 
    "scripts": ["background.js"] 
    }, 

    "content_scripts": [{ 
     "matches": ["*://*/*"], 
     "js":   ["content.js"], 
     "all_frames": true 
    }], 

    "permissions": [ 
      "tabs", 
      "*://*/*" 
    ] 
} 

background.js

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { 
    var tabStatus = changeInfo.status; 

    if (tabStatus == 'complete') { 

     function return_msg_callback() { 
      console.log('Got a msg from cs...') 
     } 

     chrome.tabs.sendMessage(tabId, { 
      text: 'hey_cs' 
     }, return_msg_callback); 
    } 

}); 

content.js

/* Listen for messages */ 
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) { 
    /* If the received message has the expected format... */ 
    if (msg.text && (msg.text == 'hey_cs')) { 
     console.log('Received a msg from bp...') 
     sendResponse('hey_bp'); 
    } 
}); 

Sau đó, nếu tôi truy cập trang web bao gồm iFrames nhiều dòng gốc, ví dụ: http://www.sport.es/ bạn sẽ thấy rằng tất cả iFrames trong trang đều nhận được thông báo từ trang nền nhưng chỉ một trong số đó có thể phản hồi lại. Đây có phải là hành vi bình thường không?

Cảm ơn trước vì câu trả lời của bạn.

+0

Cho dù đó là tình huống bình thường, trích dẫn từ tài liệu: _Nếu nhiều trang đang nghe các sự kiện onMessage, chỉ người đầu tiên gọi sendResponse() cho một sự kiện cụ thể sẽ gửi phản hồi thành công.Tất cả các phản hồi khác cho sự kiện đó sẽ bị bỏ qua._ – Xan

+0

@Xan Vì vậy, ở đây chúng tôi đang nói về tất cả các iFrames trong một trang ... do đó, theo tài liệu, tất cả các iFrames phải trả lời. Không? – jack

+0

Vì vậy, những gì tôi muốn biết là nếu một iFrame được coi là một trang duy nhất? – jack

Trả lời

7

Bạn chỉ gửi một tin nhắn có gọi lại trực tiếp để Chrome có thể sử dụng tính năng gọi lại phản hồi này chỉ một lần (đó là kết nối một lần với một thực thể, có thể là trang hoặc khung nội tuyến).

  • Giải pháp 1: gửi nhiều thông điệp cho mỗi iframe một cách rõ ràng:

    manifest.json, quyền bổ sung:

    "permissions": [ 
        "webNavigation" 
    ], 
    

    background.js

    chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { 
        ............. 
        // before Chrome 49 it was chrome.webNavigation.getAllFrames(tabId, ..... 
        // starting with Chrome 49 tabId is passed inside an object 
        chrome.webNavigation.getAllFrames({tabId: tabId}, function(details) { 
         details.forEach(function(frame) { 
          chrome.tabs.sendMessage(
           tabId, 
           {text: 'hey_cs'}, 
           {frameId: frame.frameId}, 
           function(response) { console.log(response) } 
          ); 
         }); 
        }); 
    }); 
    
  • Dung dịch 2: làm lại logic tập lệnh nền của bạn để kịch bản nội dung dẫn đầu trong giao tiếp và để cho nó gửi tin nhắn khi nó được tải.

    content.js

    chrome.runtime.sendMessage({text: "hey"}, function(response) { 
        console.log("Response: ", response); 
    }); 
    

    background.js

    chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) { 
        console.log("Received %o from %o, frame", msg, sender.tab, sender.frameId); 
        sendResponse("Gotcha!"); 
    }); 
    
+0

Tôi không hiểu giải pháp được đề xuất đầu tiên của bạn sẽ giải quyết tình huống như thế nào khi tôi gửi thư tới tập lệnh nội dung sau khi trang được tải hoàn toàn và điều này có nghĩa là, tập lệnh nội dung được tải trong trang. Btw, tôi đã thử nghiệm giải pháp được đề xuất của bạn và nó không thay đổi bất cứ điều gì. – jack

+0

Về giải pháp thứ hai của bạn, tôi không quan tâm đến thời gian tải các iframe; thực sự nếu bạn chạy mã ví dụ của tôi được đăng trong câu hỏi, bạn sẽ không bao giờ nhận được phản hồi. Nếu không, những gì bạn đề xuất không phù hợp với những gì tôi muốn làm như được mô tả trong vấn đề. Điều này là do chúng tôi muốn làm điều gì đó trong tập lệnh nội dung, chứ không phải khi tập lệnh nội dung được tải nhưng khi tải trang hoàn tất, tức là khi chúng tôi nhận được thông báo rằng tabs.trạng thái đã cập nhật hoàn tất. Điều này ngầm có nghĩa là tất cả các iFram được nạp. – jack

+0

@wOxxOm phiên bản chrome nào bạn đang chạy? theo như tôi quan tâm, tôi đang chạy 45.0.2454.99 (64 bit) và tôi chỉ thấy một phản hồi từ tập lệnh nội dung về trang nền trong bảng điều khiển nền ngay cả khi nhiều thư được gửi từ trang nền tới tập lệnh nội dung và tôi thấy các nhật ký đó trong cửa sổ bảng điều khiển công cụ dành cho nhà phát triển trang web. – jack

3

Thay vì nhắn tin, bạn có thể sử dụng executeScript cho mục đích của bạn. Trong khi lập luận của callback hiếm khi được sử dụng (và tôi không nghĩ rằng nhiều biết làm thế nào nó hoạt động), nó hoàn hảo ở đây:

chrome.tabs.executeScript(tabId, {file: "script.js"}, function(results) { 
    // Whichever is returned by the last executed statement of script.js 
    // is considered a result. 
    // "results" is an Array of all results - collected from all frames 
}) 

Bạn có thể chắc chắn rằng, ví dụ, rằng tuyên bố thực thi cuối cùng là một cái gì đó giống như

// script.js 
/* ... */ 
result = { someFrameIdentifier: ..., data: ...}; 
// Note: you shouldn't do a "return" statement - it'll be an error, 
// since it's not a function call. It just needs to evaluate to what you want. 

Đảm bảo bạn thực hiện script.js có thể thực thi nhiều lần trong cùng một ngữ cảnh.

Đối với số nhận dạng khung, bạn có thể đưa ra thuật toán của riêng mình. Có lẽ một URL là đủ, có lẽ bạn có thể sử dụng frame's position in the hierarchy.

+0

chúng ta không thể lấy frameId làm định danh khung? – jack

+0

Tôi không nghĩ một tập lệnh nội dung có thể tìm ra 'frameId' ở định dạng được sử dụng bởi các API Chrome khác. Tôi không chắc chắn 100%. – Xan

Các vấn đề liên quan