Chrome 带有 SVG 图标的扩展 (chrome.browserAction.setIcon)
Chrome extension with SVG icons (chrome.browserAction.setIcon)
我在 Chrome 扩展程序中使用可缩放 SVG 图标。
chrome.browserAction.setIcon({
tabId: tabId,
path: '../icons/' + icon + '/scalable.svg'
});
我想根据一些参数来切换图标,所以我有视觉反馈。
我意识到,当我快速切换图标时,Chrome 搞砸了,我经常看到错误的图标。我在代码中添加了 console.log
打印以确保我正确切换图标并且我发现我的代码没有错误。
看起来 Chrome 异步执行此类图标更改请求,并且 SVG 到像素的转换有时比平时花费更长的时间。这会导致执行顺序错误。
例如,如果我将图标从 A 切换到 B,然后切换到 C ;然后到 D,...最后我可能会看到 C,尽管最后的更改请求是将其切换为 D.
关于如何解决这个烦人的问题有什么想法吗?
- 使用
Promise
将调用链接到 API
- 如果您经常调用
setIcon
,请自己创建一个imageData缓存并使用它而不是path
,因为API每次都会重新读取源图标并重新创建imageData.
这是一个通用示例,未经测试:
const queue = {};
const cache = {};
// auto-clean the queue so it doesn't grow infinitely
chrome.tabs.onRemoved.addListener(tabId => delete queue[tabId]);
async function setIcon(tabId, icon) {
const url = '../icons/' + icon + '/scalable.svg';
const imageData = await (cache[url] || (cache[url] = loadImageData(url)));
queue[tabId] = (queue[tabId] || Promise.resolve()).then(() =>
new Promise(resolve =>
chrome.browserAction.setIcon({tabId, imageData}, resolve)));
}
function loadImageData(url) {
return new Promise((resolve, reject) => {
const data = {};
const img = new Image();
img.src = url;
img.onload = () => {
for (const size of [16, 32]) {
const canvas = document.createElement('canvas');
document.documentElement.appendChild(canvas);
canvas.width = canvas.height = size;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
data[size] = ctx.getImageData(0, 0, size, size);
canvas.remove();
}
resolve(data);
};
img.onerror = reject;
});
}
我在 Chrome 扩展程序中使用可缩放 SVG 图标。
chrome.browserAction.setIcon({
tabId: tabId,
path: '../icons/' + icon + '/scalable.svg'
});
我想根据一些参数来切换图标,所以我有视觉反馈。
我意识到,当我快速切换图标时,Chrome 搞砸了,我经常看到错误的图标。我在代码中添加了 console.log
打印以确保我正确切换图标并且我发现我的代码没有错误。
看起来 Chrome 异步执行此类图标更改请求,并且 SVG 到像素的转换有时比平时花费更长的时间。这会导致执行顺序错误。
例如,如果我将图标从 A 切换到 B,然后切换到 C ;然后到 D,...最后我可能会看到 C,尽管最后的更改请求是将其切换为 D.
关于如何解决这个烦人的问题有什么想法吗?
- 使用
Promise
将调用链接到 API
- 如果您经常调用
setIcon
,请自己创建一个imageData缓存并使用它而不是path
,因为API每次都会重新读取源图标并重新创建imageData.
这是一个通用示例,未经测试:
const queue = {};
const cache = {};
// auto-clean the queue so it doesn't grow infinitely
chrome.tabs.onRemoved.addListener(tabId => delete queue[tabId]);
async function setIcon(tabId, icon) {
const url = '../icons/' + icon + '/scalable.svg';
const imageData = await (cache[url] || (cache[url] = loadImageData(url)));
queue[tabId] = (queue[tabId] || Promise.resolve()).then(() =>
new Promise(resolve =>
chrome.browserAction.setIcon({tabId, imageData}, resolve)));
}
function loadImageData(url) {
return new Promise((resolve, reject) => {
const data = {};
const img = new Image();
img.src = url;
img.onload = () => {
for (const size of [16, 32]) {
const canvas = document.createElement('canvas');
document.documentElement.appendChild(canvas);
canvas.width = canvas.height = size;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
data[size] = ctx.getImageData(0, 0, size, size);
canvas.remove();
}
resolve(data);
};
img.onerror = reject;
});
}