1

我正在创建一个扩展,我需要能够在单击页面操作按钮时多次运行内容脚本。我的 background.js 中有这个:

chrome.pageAction.onClicked.addListener(function(tab) {
    alert('calling content_script');
    chrome.tabs.executeScript(null, {
        file: 'content_script.js'
    },function(){alert("success");});
});

这在第一次单击按钮时有效。第二次单击时,我的弹出窗口显示“调用 content_script”,但内容脚本从未执行。为什么是这样?

这是整个背景脚本:

function checkForValidUrl(tabId, ChangeInfo, tab){
    if(tab.url.indexOf("tiger.armstrong")> -1){
        chrome.pageAction.show(tabId);
        if(tab.url.indexOf("tiger.armstrong") == 0){
            chrome.pageAction.hide(tabId);
        }
    }
}

chrome.tabs.onUpdated.addListener(checkForValidUrl);

chrome.pageAction.onClicked.addListener(function(tab) {
    alert('calling content_script');
    chrome.tabs.executeScript(null, {
        file: 'content_script.js'
    },function(){alert("success");});
});

这是清单:

{
  "name": "LiveLab Post Grades",
  "version": "2.0",
  "permissions": [
    "activeTab","tabs","http://*/*","https://*/*"
  ],
  "background": {
    "scripts": ["jquery.min.js","background3.js"],
    "persistent": false
  },
  "page_action": {
    "default_icon": {
      "19": "GIcon.png"
  },
    "default_title": "LiveLab Tools"
  },
   "content_scripts": [ {
    "js": [ "jquery.min.js" ],
    "matches": [ "http://*/*", "https://*/*"],
    "run_at": "document_end"
  }],
  "manifest_version": 2
}

这是内容脚本:

var livelabtools = {
    /**
     * this function is like window.open, but it can POST (rather than GET) from js
     * source: http://canop.org/blog/?p=426
     */
    canop_open: function (verb, url, data, target) {
        var form = document.createElement("form");
        form.action = url;
        form.method = verb;
        form.target = target || "_self";

        if (data) {
            //for (var key in data) {
                var input = document.createElement("input");
                input.name = 'data';
                input.value = data;//typeof data[key] === "object" ? JSON.stringify(data[key]) : data[key];
                form.appendChild(input);
                //console.log(form);
            //}
        }
        // these two lines are only needed for ie
        //form.style.display = 'none';
        //document.body.appendChild(form);
        form.submit();
        console.log("form submit ===  " + form);
        form.remove();
    },
    post_grades: function () {
        alert('in post grades!!!!');
        var str, exercise,
        i = 0;
        grades = {};
        do {
            ex_str = "form1:tabSet1:tabInstr:lp2:tabSet4:tabp:lpProgress:ts1:tab7:lp7:table3:rg3:" + i + ":tc3:st3";
            lname_str = "form1:tabSet1:tabInstr:lp2:tabSet4:tabp:lpProgress:ts1:tab7:lp7:table3:rg3:" + i + ":tc1:st1";
            grade_str = "form1:tabSet1:tabInstr:lp2:tabSet4:tabp:lpProgress:ts1:tab7:lp7:table3:rg3:" + i + ":tc7:st7_field";
            exercise = document.getElementById(ex_str);
            lname = document.getElementById(lname_str);
            grade = document.getElementById(grade_str);
            if (exercise != null) {
                if (grades[lname.innerHTML] === undefined)
                    grades[lname.innerHTML] = {};
                    console.log(lname.innerHTML + ", " + exercise.innerHTML + ", " + grade.innerHTML);
                if (grade.value != null && grade.value != '')
                    grades[lname.innerHTML][exercise.innerHTML] = grade.value;
                else
                    grades[lname.innerHTML][exercise.innerHTML] = "0";
            }
            i++;
        } while (exercise != null);
       // console.log(JSON.stringify(grades));
       // console.log(JSON.stringify(grades).length)
        //window.open("http://aspen2.cscofc.info/jsontocsv.php?data="+JSON.stringify(grades));
        console.log('posting...' + "\n JSON.String... = "+ JSON.stringify(grades));
        livelabtools.canop_open("post", "http://aspen2.cscofc.info/jsontocsv.php", JSON.stringify(grades));        
        console.log('done');
        return "function end";
    }
}

console.log(livelabtools.post_grades());

除非被问到,否则我不会详细介绍它,但要注意的重要部分是返回语句和控制台日志。第一次单击页面操作按钮时,一切运行良好,完成后,我将“功能结束”打印到控制台。但是,在初始运行之后,每当我单击页面操作按钮时,我都会收到一条警报,提示“正在调用 content_script”,并且没有其他任何事情发生。为什么我的内容脚本不会多次运行?

4

1 回答 1

2

似乎当脚本已经被注入时,它不会再次被注入。
因此,要走的路是通过将消息传递给内容脚本来启动您的操作。(当然,如果内容脚本还没有注入,则需要先注入。)

我想出的一种解决方案(经过测试确认它可以正常工作)如下:

  1. pageAction.onClicked后台页面向内容脚本发送消息,要求它做某事(例如发布成绩)。此外,请求将响应发送回后台页面。
    [另请参见chrome.tabs.sendMessage(...)。]

  2. 如果内容脚本已经被注入,让它接收消息,将确认发送回后台页面并继续做一些事情(例如发布成绩)。此过程可以根据需要进行多次。
    [另见chrome.runtime.onMessage。]

  3. 第一次pageAction.onClicked触发时,不会有内容脚本监听消息。在这种情况下,将不会有消息确认。相反chrome.runtime.lastError将被设置。在这种情况下,后台页面必须先注入内容脚本,然后再次发送消息。
    [另见chrome.runtime.lastError。]


从理论上讲,应该这样做!
实际上,这是对我有用的示例代码:

manifest.json:(注意:如果您对需要访问的页面有更具体的要求,您可以将它们合并到清单中并去掉一些权限。)

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

    "page_action": {
        "default_title": "Test Extension"
    },

    "permissions": [
        "tabs",
        "http://*/*",
        "https://*/*"
    ]
    ...
}

背景.js:

function checkForValidURL(tabId, info, tab) {
    var idx = tab.url.indexOf("tiger.armstrong");
    if (idx > 0) {
        chrome.pageAction.show(tabId);
    } else {
        chrome.pageAction.hide(tabId);
    }
}
chrome.tabs.onUpdated.addListener(checkForValidURL);

function onPageActionClicked(tab) {
    // Send message to content script, asking to post grades
    alert("Calling content_script...");
    chrome.tabs.sendMessage(tab.id, { action: "postGrades" }, function() {
        if (chrome.runtime.lastError) {
            // The error indicates that the content script
            // has not been injected yet. Inject it and...
            chrome.tabs.executeScript(tab.id, {
                file: "content.js"
            }, function() {
                if (!chrome.runtime.lastError) {
                    // ...if injected successfully, send the message anew
                    onPageActionClicked(tab);
                }
            });
        } else {
            // The content script called our response callback,
            // confirming that it is there and got our message
            alert("Message got through !");
        }
    });
};
chrome.pageAction.onClicked.addListener(onPageActionClicked);

内容.js:

var livelabtools = {
    /**
     * This function is like window.open, but it can POST (rather than GET) from
     * JS source: http://canop.org/blog/?p=426
     */
    canop_open: function (method, url, data, target) {
        var form = document.createElement("form");
        form.action = url;
        form.method = method;
        form.target = target || "_self";

        // 'data' is an object with key-value pairs
        // of fields to be sent
        if (data) {
            for (var key in data) {
                var input = document.createElement("input");
                input.name = key;
                input.value = (typeof(data[key]) === "object")
                        ? JSON.stringify(data[key]) : data[key];
                form.appendChild(input);
            }
        }

        form.submit();
        form.remove();
    },
    post_grades: function () {
        console.log("Posting some grades...");
        livelabtools.canop_open("POST",
                "http://aspen2.cscofc.info/jsontocsv.php", 
                "{}");
        console.log("Grades sent !");
    }
}

// Listen for messages from the background page
// (It actually listens for messages from anyone in the context,
//  but the background page is the one that interrests us)
chrome.runtime.onMessage.addListener(function(msg, sender, response) {
    // If we've been asked to post grades...
    if (msg.action && (msg.action == "postGrades")) {
        // ...confirm we got the message and...
        response();
        // ...do what we do best: post grades !
        livelabtools.post_grades();
    }
});

让我们希望这涵盖了它:)

于 2013-10-28T17:01:44.197 回答