Javascript 为什么我的Chrome扩展弹出窗口没有重新绘制?
我正在为我们基于网络的产品的内部用户编写一个Google Chrome扩展,他们可以在这里管理他们的功能标志。这是一个简单的用户界面,其中包括一个需要接受的通知、一个人们可以为自己输入新功能标志的文本区域,以及一个带有删除按钮和复选框的标志列表。然后,每当您访问产品时,扩展就会自动将标志添加到查询参数中,以便启用它们 这太棒了!至少在大多数情况下。。我还没有弄清楚原因,但是有些情况下,用户点击图标,弹出窗口打开,弹出窗口的html没有正确响应。单击“切换”不会取消选中复选框,单击“删除”按钮不会删除功能标志,并且在开始键入后,聚焦文本框不会显示光标或任何文本。但是,如果您进行了更改并关闭并重新打开弹出窗口,则更改会被保存 任何帮助都将不胜感激 下面是代码。不相关的零件已替换为Javascript 为什么我的Chrome扩展弹出窗口没有重新绘制?,javascript,html,google-chrome-extension,Javascript,Html,Google Chrome Extension,我正在为我们基于网络的产品的内部用户编写一个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("&")}`
});
}
}
});