Javascript 为什么我的Chrome扩展弹出窗口没有重新绘制?

Javascript 为什么我的Chrome扩展弹出窗口没有重新绘制?,javascript,html,google-chrome-extension,Javascript,Html,Google Chrome Extension,我正在为我们基于网络的产品的内部用户编写一个Google Chrome扩展,他们可以在这里管理他们的功能标志。这是一个简单的用户界面,其中包括一个需要接受的通知、一个人们可以为自己输入新功能标志的文本区域,以及一个带有删除按钮和复选框的标志列表。然后,每当您访问产品时,扩展就会自动将标志添加到查询参数中,以便启用它们 这太棒了!至少在大多数情况下。。我还没有弄清楚原因,但是有些情况下,用户点击图标,弹出窗口打开,弹出窗口的html没有正确响应。单击“切换”不会取消选中复选框,单击“删除”按钮不会

我正在为我们基于网络的产品的内部用户编写一个Google Chrome扩展,他们可以在这里管理他们的功能标志。这是一个简单的用户界面,其中包括一个需要接受的通知、一个人们可以为自己输入新功能标志的文本区域,以及一个带有删除按钮和复选框的标志列表。然后,每当您访问产品时,扩展就会自动将标志添加到查询参数中,以便启用它们

这太棒了!至少在大多数情况下。。我还没有弄清楚原因,但是有些情况下,用户点击图标,弹出窗口打开,弹出窗口的html没有正确响应。单击“切换”不会取消选中复选框,单击“删除”按钮不会删除功能标志,并且在开始键入后,聚焦文本框不会显示光标或任何文本。但是,如果您进行了更改并关闭并重新打开弹出窗口,则更改会被保存

任何帮助都将不胜感激

下面是代码。不相关的零件已替换为
SNIP

manifest.json

{
    "name": "SNIP",
    "version": "1.0",
    "description": "SNIP",
    "browser_action": {
        "default_title": "SNIP",
        "default_icon": "SNIP.png",
        "default_popup": "popup.html"
    },
    "background": {
        "scripts": ["background.js"],
        "persistent": false
    },
    "manifest_version": 2,
    "permissions": [
        "storage",
        "webNavigation",
        "tabs"
    ]
}
popup.html

<html>
    <head>
        <style>
            SNIP
        </style>
    </head>
    <body>
        <h3>Important notice:</h3>
        <ol>
            SNIP (just some li's with text in here)
        </ol>
        <button id="accept-notice">Accept</button>
        <div id="feature-flag-container" class="hidden">
            <h3>Feature flags:</h3>
            <div id="feature-flag-list"></div>
            <input id="new-feature-flag" type="text" />
        </div>
        <script type="text/javascript" src="popup.js"></script>
    </body>
</html>
background.js

const urls = [SNIP];
const environments = [SNIP];
const worksOn = [SNIP];
const options = [];
urls.forEach(url => {
    environments.forEach(environment => {
        worksOn.forEach(link => {
            options.push(`https://${url}${environment}.SNIP.com/${link}/`);
        });
    });
});

const state = { acceptedNotice: false, featureFlags: {} };
chrome.storage.sync.get(["acceptedNotice", "featureFlags"], result => {
    state.acceptedNotice = result.acceptedNotice;
    state.featureFlags = result.featureFlags || {};
});

chrome.runtime.onMessage.addListener(({ msg, flag, value }) => {
    if (msg === "open_popup") {
        chrome.runtime.sendMessage(state);
        return
    }

    if (msg === "accept_notice") {
        state.acceptedNotice = true;
    } else if (msg === "add_flag") {
        state.featureFlags[flag] = true;
    } else if (msg === "remove_flag") {
        delete state.featureFlags[flag];
    } else if (msg === "toggle_flag") {
        state.featureFlags[flag] = value;
    }
    chrome.storage.sync.set(state);
});

chrome.webNavigation.onBeforeNavigate.addListener(event => {
    if (options.find(option => event.url.indexOf(option) === 0)) {
        const flags = Object.keys(state.featureFlags).filter(flag => state.featureFlags[flag] === true)
        const url = event.url.split("?");
        const queryParams = (url[1] || "").split("&").filter(param => !!param).map(param => {
            const split = param.split("=");
            return { key: split[0], value: split[1] };
        });
        const initialLength = queryParams.length;
        flags.forEach(flag => {
            if (!queryParams.find(param => param.key === flag)) {
                queryParams.push({ key: flag });
            }
        });
        if (queryParams.length !== initialLength) {
            chrome.tabs.update(event.tabId, {
                url: `${url[0]}?${queryParams.map(param =>
                    param.value ? `${param.key}=${param.value}` : param.key
                ).join("&")}`
            });
        }
    }
});

您正在使用一个事件页面,该页面在其自身处于不活动状态5秒后卸载,因此当它下次自动加载时,状态变量都为空。1) 您根本不需要维护任何全局变量:只需在popup.js中使用chrome.storage。2) 您可以注销webNavigation侦听器,然后使用URL筛选器参数再次注册它(它应该是一个命名的全局函数),以便Chrome仅在URL匹配时触发它。3) 您应该通过sendResponse发送响应,而不是发送响应消息,如中所示。您对事件页面的含义是什么?无论哪种方式,我认为弹出窗口的状态丢失都是好的,因为它在下次打开时会重新实例化自己。不,这不是好的,当onMessage被触发时,状态不会重建。事件页面是用persistent:false声明的背景页面。我今天做了更多的研究,现在意识到我误解了。你说的是
background.js
的状态,我以为你说的是
popup.js
。我注意到,即使
background.js
popup.js
中没有代码没有加载到html中,弹出窗口也没有响应。本机文本输入未获得焦点或显示任何键入的字符。但是,当我从
manifest.json
中删除
background
部分时,一切都按预期进行。如果不亲自在本地尝试,我就无法添加任何内容,因为概要无法计算。您使用的是一个事件页面,它在自身不活动5秒后卸载,因此下次自动加载时,状态变量都为空。1) 您根本不需要维护任何全局变量:只需在popup.js中使用chrome.storage。2) 您可以注销webNavigation侦听器,然后使用URL筛选器参数再次注册它(它应该是一个命名的全局函数),以便Chrome仅在URL匹配时触发它。3) 您应该通过sendResponse发送响应,而不是发送响应消息,如中所示。您对事件页面的含义是什么?无论哪种方式,我认为弹出窗口的状态丢失都是好的,因为它在下次打开时会重新实例化自己。不,这不是好的,当onMessage被触发时,状态不会重建。事件页面是用persistent:false声明的背景页面。我今天做了更多的研究,现在意识到我误解了。你说的是
background.js
的状态,我以为你说的是
popup.js
。我注意到,即使
background.js
popup.js
中没有代码没有加载到html中,弹出窗口也没有响应。本机文本输入未获得焦点或显示任何键入的字符。但是,当我从
manifest.json
中删除
background
部分时,一切都按预期进行。如果我自己不在本地尝试,我就无法添加任何内容,因为概要无法计算。
const urls = [SNIP];
const environments = [SNIP];
const worksOn = [SNIP];
const options = [];
urls.forEach(url => {
    environments.forEach(environment => {
        worksOn.forEach(link => {
            options.push(`https://${url}${environment}.SNIP.com/${link}/`);
        });
    });
});

const state = { acceptedNotice: false, featureFlags: {} };
chrome.storage.sync.get(["acceptedNotice", "featureFlags"], result => {
    state.acceptedNotice = result.acceptedNotice;
    state.featureFlags = result.featureFlags || {};
});

chrome.runtime.onMessage.addListener(({ msg, flag, value }) => {
    if (msg === "open_popup") {
        chrome.runtime.sendMessage(state);
        return
    }

    if (msg === "accept_notice") {
        state.acceptedNotice = true;
    } else if (msg === "add_flag") {
        state.featureFlags[flag] = true;
    } else if (msg === "remove_flag") {
        delete state.featureFlags[flag];
    } else if (msg === "toggle_flag") {
        state.featureFlags[flag] = value;
    }
    chrome.storage.sync.set(state);
});

chrome.webNavigation.onBeforeNavigate.addListener(event => {
    if (options.find(option => event.url.indexOf(option) === 0)) {
        const flags = Object.keys(state.featureFlags).filter(flag => state.featureFlags[flag] === true)
        const url = event.url.split("?");
        const queryParams = (url[1] || "").split("&").filter(param => !!param).map(param => {
            const split = param.split("=");
            return { key: split[0], value: split[1] };
        });
        const initialLength = queryParams.length;
        flags.forEach(flag => {
            if (!queryParams.find(param => param.key === flag)) {
                queryParams.push({ key: flag });
            }
        });
        if (queryParams.length !== initialLength) {
            chrome.tabs.update(event.tabId, {
                url: `${url[0]}?${queryParams.map(param =>
                    param.value ? `${param.key}=${param.value}` : param.key
                ).join("&")}`
            });
        }
    }
});