首页 > 解决方案 > 为什么我的 Chrome 扩展弹出窗口没有重新绘制?

问题描述

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

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

任何帮助将非常感激。

下面是代码。不相关的部分已替换为SNIP

清单.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>

popup.js

const acceptNoticeButton = document.getElementById("accept-notice");
const featureFlagContainer = document.getElementById("feature-flag-container");
const featureFlagList = document.getElementById("feature-flag-list");
const newFeatureFlagInput = document.getElementById("new-feature-flag");

let existingFlags = [];

chrome.runtime.sendMessage({ msg: "open_popup" });
chrome.runtime.onMessage.addListener(request => {
    Object.keys(request.featureFlags).forEach(flag => {
        addFeatureFlagNode(flag, !!request.featureFlags[flag]);
    });
    if (request.acceptedNotice) {
        acceptNoticeButton.click();
    }
});

acceptNoticeButton.onclick = () => {
    chrome.runtime.sendMessage({ msg: "accept_notice" });
    acceptNoticeButton.classList.add("hidden");
    featureFlagContainer.classList.remove("hidden");
}

function removeFeatureFlag(e) {
    const parent = e.target.parentNode;
    const flag = e.target.parentNode.children[1].innerText;

    existingFlags = existingFlags.filter(f => f !== flag);

    parent.remove();
    chrome.runtime.sendMessage({ msg: "remove_flag", flag });
}

function toggleFeatureFlag(e) {
    const flag = e.target.parentNode.children[1].innerText;
    const value = e.target.checked === true;
    chrome.runtime.sendMessage({ msg: "toggle_flag", flag, value });
}

function addFeatureFlagNode(flag, checked) {
    existingFlags.push(flag);

    const checkbox = document.createElement("input");
    checkbox.type = "checkbox";
    checkbox.checked = checked === false ? false : true;
    checkbox.onchange = toggleFeatureFlag;

    const text = document.createElement("p");
    text.innerText = flag;

    const del = document.createElement("button");
    del.innerText = "Delete";
    del.onclick = removeFeatureFlag;

    const container = document.createElement("div");
    container.appendChild(checkbox);
    container.appendChild(text);
    container.appendChild(del);

    featureFlagList.appendChild(container);
}

newFeatureFlagInput.onkeydown = e => {
    const flag = e.target.value;
    if (e.key === "Enter" && flag && !existingFlags.includes(flag)) {
        chrome.runtime.sendMessage({ msg: "add_flag", flag });
        addFeatureFlagNode(flag);
        e.target.value = "";
    }
}

背景.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("&")}`
            });
        }
    }
});

标签: javascripthtmlgoogle-chrome-extension

解决方案


推荐阅读