请注意,我正在使用Babel
+ Webpack
生成ES2017
代码ES5
(我正在使用async
await
个功能并且希望在旧浏览器中使用相同的代码并减少更改。
我的目标是在特定标签上执行#代码。这些代码包括,提交表单,点击链接等...重定向到新的网页。在页面加载之前应该暂停什么代码并不重要它导航/重定向的页面是什么。所以要模拟重定向,我正在使用window.location = "https://facebook.com"
。
简而言之。预期的行为是,
url: 'https://google.com'
https://facebook.com
facebook
后显示提醒消息。我有以下帮助班。
/** Tabs class will provide promisify chrome.tabs functions */
export default class Tabs {
/** Creates a new tab using passed configurations
* @param {Object} config
* {Number} windowId
* {Number} index
* {String} url
* {Boolean} active
* {Boolean} pinned
* {Number} openerTabId ID of the tab that opened current tab. should be in the same window.
* @returns {Promise}
*/
static create(config) {
// Return new promise
return new Promise((resolve, reject) => {
// Creating new tab
chrome.tabs.create(config, (tab) => {
// Error
if (chrome.runtime.lastError)
reject(chrome.extension.lastError);
// Success
else
resolve(tab);
});
});
}
/**
*
* @param {Number} id
* @param {Object} config
* {String} code // javascript or css code to inject
* {String} file // javascript or css file to inject
* {Boolean} allFrames // inject to all frames
* {Number} frameId // frame index to inject
* {Boolean} matchAboutBlank // inject tp about:blank pages
* {String} runAt // "document_start" or "document_end" or "document_idle"
* @returns {Promise}
*/
static execute(id, config) {
// Return a new promise
return new Promise((resolve, reject) => {
// Execute a script
chrome.tabs.executeScript(id, config, (results) => {
// Error
if (chrome.runtime.lastError)
reject(chrome.runtime.las2tError);
// Success
else{
resolve(results);
// print "execute" just to get the idea when it's printed.
console.log('executed: ' + config.code);
}
});
})
}
/**
*
* @param {Number} id
* @returns {Promise}
*/
static get(id) {
// Return new promise
return new Promise((resolve, reject) => {
// Get tab
chrome.tabs.get(id, (tab) => {
// Error
if(chrome.runtime.lastError)
reject(chrome.runtime.lastError);
// Success
else
resolve(tab);
});
});
}
}
export default class Process {
/** Pause for a given time
* @param ms
* @returns {Promise}
*/
static timeout(ms) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, ms);
});
}
}
最后,我的background.js
用于收听webNavigation.onBeforeNavigate
和webNavigation.onCompleted
并执行脚本。
请注意,onBeforeNavigate
和onCompleted
提供了有关每个标签的详细信息,但是当我运行此标签时,我只有一个标签。所以我在没有isTabStatus
验证的情况下直接初始化tabId
。
import Tabs from "./tab/tabs";
import Process from "./commons/process";
// holds the status of new tab.
let isTabStatus = "loading";
/**
* Listeners
*/
chrome.webNavigation.onBeforeNavigate.addListener((info) => {
if(info.frameId === 0) {
console.log('before navigation status: loading ' + info.url);
isTabStatus = "loading";
}
});
chrome.webNavigation.onCompleted.addListener((info) => {
if(info.frameId === 0) {
console.log('on completed status: completed ' + info.url);
isTabStatus = "completed";
}
});
async function run() {
let tab = await Tabs.create({
url: "https://www.google.com"
});
let tabId = tab.id;
await waitUntilLoaded();
await Tabs.execute(tabId, {
code: "window.location = 'https://facebook.com'",
runAt: "document_idle"
});
await waitUntilLoaded();
await Tabs.execute(tabId, {
code: "alert('hello world')"
});
}
async function waitUntilLoaded () {
while(isTabStatus === "loading") {
await Process.timeout(400);
console.log('waiting');
}
}
run();
所以,预期的行为是,
https://google.com
https://facebook.com
hello world
。但它确实是,
https://google.com
hello world
https://facebook.com
最后,控制台记录如下。
before navigation status: loading https://www.google.com/
waiting
on completed status: completed https://www.google.lk/?gfe_rd=cr&ei=VIueWa2uFZOCuATNtJTIBA
waiting
execute: window.location = 'https://facebook.com'
before navigation status: loading https://facebook.com/
execute: alert('hello world')
on completed status: completed https://www.facebook.com/
此处alert
已完成onBeforeNavigate
后执行,但实际alert
消息显示在google
页面中。只有在我点击确定(警报消息确定)之后,它才会重定向到facebook
。
很明显,如果我在console.log
之前添加alert
,如下所示。
await waitUntilLoaded();
console.log('****');
await Tabs.execute(tabId, {
code: "alert('hello world')"
});
然后最终的日志将是,
before navigation status: loading https://www.google.com/
waiting
on completed status: completed https://www.google.lk/?gfe_rd=cr&ei=TY-eWb_0D6baugTMqqWACQ
waiting
execute: window.location = 'https://facebook.com'
****
before navigation status: loading https://facebook.com/
execute: alert('hello world')
on completed status: completed https://www.facebook.com/
正如您可以看到警告在window.location
更改后立即执行。甚至在onBeforeNavigation
回调
在下面找到其他详细信息。
{
"manifest_version": 2,
"name": "Tax Executer",
"description": "",
"version": "1.0",
"browser_action": {
"default_icon": "images/icon.png",
"default_popup": "views/popup.html"
},
"permissions": [
"webNavigation",
"webRequest",
"activeTab",
"tabs",
"http://*/",
"https://*/",
"file:///*/"
],
"background": {
"page": "views/background.html"
},
"content_scripts": [{
"run_at": "document_start",
"matches": ["https://*/*", "file://*/*"],
"js": ["dist/content.js"]
}],
"automation": {}
}
{
"name": "babel_webpack_starter_project",
"version": "1.0.0",
"description": "helps you to get started with babel + webpack project quickly",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"webpack": "webpack",
"babel": "babel"
},
"repository": {
"type": "git",
"url": "git+https://github.com/SrineshNisala/babel_webpack_starter_project.git"
},
"keywords": [
"babel",
"webpack",
"starter"
],
"author": "SrineshNisala",
"license": "MIT",
"bugs": {
"url": "https://github.com/SrineshNisala/babel_webpack_starter_project/issues"
},
"homepage": "https://github.com/SrineshNisala/babel_webpack_starter_project#readme",
"devDependencies": {
"assert": "^1.4.1",
"babel-cli": "^6.24.1",
"babel-core": "^6.25.0",
"babel-loader": "^7.1.1",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-plugin-unassert": "^2.1.2",
"babel-preset-es2015": "^6.24.1",
"babel-preset-es2016": "^6.24.1",
"babel-preset-es2017": "^6.24.1",
"babel-preset-stage-1": "^6.24.1",
"webpack": "^3.4.1"
},
"dependencies": {
"enumify": "^1.0.4",
"socket.io-client": "^2.0.3"
}
}
const path = require('path');
module.exports = {
entry: {
background: "./src/background.js",
content: "./src/content.js",
popup: "./src/popup.js"
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: "[name].js"
},
module: {
loaders: [{
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: ["es2015", "es2016", "es2017", "stage-1"],
plugins: [
"transform-runtime",
// "babel-plugin-unassert"
]
}
}]
}
};
要运行,请将所有文件放在文件夹中使用npm install
来安装所有依赖项。并使用npm run webpack
将代码编译为dist文件夹。使用dist文件夹background.js
作为background script
。
没有babel
或webpack
的相同流程,即使没有任何promises
也是如此。找到下面的background.js
var isCompleted = false;
chrome.webNavigation.onBeforeNavigate.addListener((info) => {
if(info.frameId === 0) {
console.log('before navigation ' + info.url);
isCompleted = false;
}
});
chrome.webNavigation.onCompleted.addListener((info) => {
if(info.frameId === 0) {
console.log('on completed ' + info.url);
isCompleted = true;
}
});
// Create tab
chrome.tabs.create({
url: "https://google.com"
}, (tab) => {
console.log("tab created");
// Navigate to facebook.com
chrome.tabs.executeScript({
code: "window.location = 'https://www.facebook.com'",
runAt: "document_idle"
}, () => {
console.log("window location changed, current tabs is completed: " + isCompleted);
// Wait until facebook is loaded
if(!isCompleted) {
console.log('waiting until facebook is loaded');
setTimeout(() => {
// Alert hello world
chrome.tabs.executeScript({
code: "alert('hello world')",
runAt: "document_idle"
}, () => {
console.log("alert executed");
});
}, 5000);
} else {
console.log("**** tab status has not been changed even if it's navigating to facebook.com ****");
chrome.tabs.executeScript({
code: "alert('hello world')",
runAt: "document_idle"
}, () => {
console.log("alert executed");
});
}
});
});
结果我和以前一样。 console.log as below
tab created
before navigation https://google.com/
on completed https://www.google.lk/?gfe_rd=cr&ei=CVCfWervItzLugSemrqAAw
window location changed, current tabs is completed: true
**** tab status has not been changed even if it's navigating to facebook.com ****
before navigation https://www.facebook.com/
alert executed
on completed https://www.facebook.com/
执行window.location
后,我猜当前页面卸载与新页面加载之间存在一点时间差距。所以我在window.onBeforeUnload
中听了content script
事件,并在发生后将消息传递给运行时。
window.addEventListener('beforeunload', (event) => {
chrome.runtime.sendMessage({type: "onbeforeunload"});
});
我收听了来自background script
的消息。
var isCompleted = false;
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if(request.type === "onbeforeunload") {
console.log("page is unloading");
isCompleted = false;
}
}
);
但最终在webNavigation.onBeforeNavigate
回调之后收到此消息。