window.location更改

时间:2017-08-24 12:50:04

标签: javascript google-chrome google-chrome-extension webpack babel

请注意,我正在使用Babel + Webpack生成ES2017代码ES5(我正在使用async await个功能并且希望在旧浏览器中使用相同的代码并减少更改。

我的目标是在特定标签上执行#代码。这些代码包括,提交表单,点击链接等...重定向到新的网页。在页面加载之前应该暂停什么代码并不重要它导航/重定向的页面是什么。所以要模拟重定向,我正在使用window.location = "https://facebook.com"

简而言之。预期的行为是,

  1. 我用url: 'https://google.com'
  2. 打开标签
  3. 将窗口位置更改为https://facebook.com
  4. 完全加载facebook后显示提醒消息。
  5. 我有以下帮助班。

    tabs.js

    /** 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);
                });
            });
        }
    }
    

    process.js

    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.onBeforeNavigatewebNavigation.onCompleted并执行脚本。

    请注意,onBeforeNavigateonCompleted提供了有关每个标签的详细信息,但是当我运行此标签时,我只有一个标签。所以我在没有isTabStatus验证的情况下直接初始化tabId

    background.js

    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();
    

    所以,预期的行为是,

    1. 创建新标签
    2. 导航至https://google.com
    3. 导航至https://facebook.com
    4. 提醒hello world
    5. 但它确实是,

      1. 创建新标签
      2. 导航至https://google.com
      3. 提醒hello world
      4. 导航至https://facebook.com
      5. 最后,控制台记录如下。

        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回调

        之前

        在下面找到其他详细信息。

        mainfest.json

        {
          "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": {}
        }
        

        的package.json

        {
          "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"
          }
        }
        

        webpack.config.js

        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

        我试过

        没有babelwebpack的相同流程,即使没有任何promises也是如此。找到下面的background.js

        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事件,并在发生后将消息传递给运行时。

        content.js

        window.addEventListener('beforeunload', (event) => {
            chrome.runtime.sendMessage({type: "onbeforeunload"});
        });
        

        我收听了来自background script的消息。

        background.js

        var isCompleted = false;
        
        
        chrome.runtime.onMessage.addListener(
            function(request, sender, sendResponse) {
                if(request.type === "onbeforeunload") {
                    console.log("page is unloading");
                    isCompleted = false;
                }
            }
        );
        

        但最终在webNavigation.onBeforeNavigate回调之后收到此消息。

0 个答案:

没有答案