首页 > 解决方案 > 有没有办法为上下文菜单项定义自己的上下文(谷歌浏览器扩展)

问题描述

我有一个简单的 chrome 扩展,我的目标是悬停任何 img 或视频或音频标签,通过右键单击 img、视频或音频来获取包含我的扩展项的上下文菜单。

所以问题是,当某些 img 在 div 内部或后面时,我无法获取我的上下文菜单项,因为它与我的上下文不匹配。视频和音频有时也会发生同样的事情。我的问题是有什么方法可以编写我自己的上下文而不是使用谷歌的“图像”、“视频”、“音频”。

我已经有了有时可以工作的扩展,所以我需要用一些图像来解决这个问题。

var contextMenuItem = {
    "id": "printData",
    "title": "print",
    "contexts": ["image", "audio", "video"]
};

chrome.contextMenus.removeAll(function() {
    chrome.contextMenus.create(contextMenuItem)
});

chrome.contextMenus.onClicked.addListener(function(mediaData){
    if (mediaData.menuItemId == "printData") {
        console.log(mediaData)
    }
});

所以我想要的是当我在页面上显示任何图像时显示我的上下文菜单项。因为现在它可能有 50% 的时间有效。谢谢

标签: javascriptgoogle-chrome-extension

解决方案


不,没有办法添加自定义上下文。

您可以做的是在上下文中注册一个额外的菜单项,使用内容脚本中的事件侦听器"page"单独id动态显示/隐藏它。mousedown监听器将在事件之前触发,contextmenu如果事件的目标包含 img/media 则通知后台脚本。后台脚本将使用 chrome.contextMenus API 来切换菜单项。

内容脚本

// true means 'useCapture' mode (the first event phase)
window.addEventListener('mousedown', e => button === 2 && beforeContextMenu(e), true);
window.addEventListener('keydown', e => {
  if (e.key === 'ContextMenu' || 
      e.key === 'F10' && e.shiftKey && !e.altKey && !e.ctrlKey && !e.metaKey) {
    beforeContextMenu(e);
  }
}, true);

function beforeContextMenu(e) {
  const el = !e.target.matches('img, video, audio') &&
             e.target.querySelector('img, video, audio');
  chrome.runtime.sendMessage({
    contextMenu: el ? el.currentSrc || el.src : '',
  });
}

背景脚本

chrome.runtime.onMessage.addListener((message, sender) => {
  if (message.contextMenu) {
    chrome.contextMenus.create({
      id: 'printData:page',
      title: 'print',
      contexts: ['page'],
    }, ignoreChromeError);
  } else if (message.contextMenu === '') {
    chrome.contextMenus.remove('printData:page', ignoreChromeError);
  }
});

chrome.runtime.onInstalled.addListener(() => {
  chrome.contextMenus.create({
    id: 'printData',
    title: 'print',
    contexts: ['image', 'audio', 'video'],
  }, ignoreChromeError);
});

chrome.contextMenus.onClicked.addListener(e => {
  if (e.menuItemId.startsWith('printData')) {
    console.log(e);
  }
});

function ignoreChromeError() {
  return chrome.runtime.lastError;
}

不过,这个简化的示例将为所有选项卡全局切换菜单项。Chrome API 无法切换每个选项卡的菜单,因此您可能想要实现的最接近的事情是使用 documentUrlPatterns 来指定选项卡 URL,但这是一个可能不值得追求的边缘情况。


推荐阅读