为什么捐赠
API 资源管理器
Quasar CLI with Vite - @quasar/app-vite
BEX 类型

正如我们已经讨论过的,Quasar 可以处理浏览器扩展可以存在的各种位置,即新标签页、网页、开发者工具选项或弹出窗口。你不需要为每个位置创建一个单独的 Quasar 应用。你可以使用路由器来完成一些方便的工作。

新标签页

这是 BEX 运行的默认方式。可以通过点击浏览器中的 BEX 图标访问。Quasar 应用将在新(空白)标签页中运行。

开发者工具、选项和弹出窗口

这些都遵循相同的模式,设置一个路由并配置 manifest.json 文件,以便当它尝试显示其中任何一种类型时,它会查看该路由。例如

routes.js

const routes = [
  { path: '/options', component: () => import('pages/OptionsPage.vue') },
  { path: '/popup', component: () => import('pages/PopupPage.vue') },
  { path: '/devtools', component: () => import('pages/DevToolsPage.vue') }
]

您可以使用以下配置来配置 manifest.json 文件,以便选项页面从该路由加载

manifest v2

{
  "manifest_version": 2,

  "options_page": "www/index.html#/options", // Options Page
  "browser_action": {
    "default_popup": "www/index.html#/popup" // Popup Page
  },
  "devtools_page": "www/index.html#/devtools", // Dev Tools
}

manifest v3

{
  "manifest_version": 3,

  "action": {
    "default_popup": "www/index.html#/popup" // Popup Page
  },
  "options_page": "www/index.html#/options", // Options Page
  "devtools_page": "www/index.html#/devtools", // Dev Tools
}

网页

这才是真正强大的功能。只要有一点巧思,我们就可以将我们的 Quasar 应用注入到网页中,并将其用作覆盖层,使其看起来像我们的 Quasar 应用是页面体验的一部分。

以下是实现此功能的简要概述

  • src-bex/my-content-script.js

这里的想法是创建一个 IFrame,并将我们的 Quasar 应用添加到其中,然后将其注入到页面中。

鉴于我们的 Quasar 应用程序可能需要占用整个窗口高度(从而阻止与底层页面的任何交互),我们有一个事件来处理设置 IFrame 的高度。默认情况下,IFrame 的高度只够显示 Quasar 工具栏(并允许与页面其余部分进行交互)。

/src-bex/my-content-script.js

// Hooks added here have a bridge allowing communication between the BEX Content Script and the Quasar Application.
// More info: https://quasar.org.cn/quasar-cli/developing-browser-extensions/content-hooks
import { bexContent } from 'quasar/wrappers'

const
  iFrame = document.createElement('iframe'),
  defaultFrameHeight = '62px'

/**
 * Set the height of our iFrame housing our BEX
 * @param height
 */
const setIFrameHeight = height => {
  iFrame.height = height
}

/**
 * Reset the iFrame to its default height e.g The height of the top bar.
 */
const resetIFrameHeight = () => {
  setIFrameHeight(defaultFrameHeight)
}

/**
 * The code below will get everything going. Initialize the iFrame with defaults and add it to the page.
 * @type {string}
 */
iFrame.id = 'bex-app-iframe'
iFrame.width = '100%'
resetIFrameHeight()

// Assign some styling so it looks seamless
Object.assign(iFrame.style, {
  position: 'fixed',
  top: '0',
  right: '0',
  bottom: '0',
  left: '0',
  border: '0',
  zIndex: '9999999', // Make sure it's on top
  overflow: 'visible'
})

;(function () {
  // When the page loads, insert our browser extension app.
  iFrame.src = chrome.runtime.getURL('www/index.html')
  document.body.prepend(iFrame)
})()

export default bexContent((bridge) => {
  /**
   * When the drawer is toggled set the iFrame height to take the whole page.
   * Reset when the drawer is closed.
   */
  bridge.on('wb.drawer.toggle', ({ data, respond }) => {
    if (data.open) {
      setIFrameHeight('100%')
    } else {
      resetIFrameHeight()
    }
    respond()
  })
})

我们可以在任何知道要打开抽屉并因此更改 IFrame 的高度以允许整个抽屉可见的时候,从我们的 Quasar 应用程序调用此事件。

  • src-bex/assets/content.css

在文档顶部添加边距,以便我们的 Quasar 工具栏不会与实际页面内容重叠。

.target-some-header-class {
  margin-top: 62px;
}
  • Quasar 应用程序 (/src)

然后,在我们的 Quasar 应用程序 (/src) 中,我们有一个函数可以切换抽屉,并向内容脚本发送一个事件,告诉它调整 IFrame 的大小,从而允许我们的整个应用程序可见。

<q-drawer :model-value="drawerIsOpen" @update:model-value="drawerToggled">
  Some Content
</q-drawer>
import { useQuasar } from 'quasar'
import { ref } from 'vue'

setup () {
  const $q = useQuasar()
  const drawerIsOpen = ref(true)

  async function drawerToggled () {
    await $q.bex.send('wb.drawer.toggle', {
      open: drawerIsOpen.value // So it knows to make it bigger / smaller
    })

    // Only set this once the promise has resolved so we can see the entire slide animation.
    drawerIsOpen.value = !drawerIsOpen.value
  }

  return { drawerToggled }
}

现在,您已在网页中运行了一个 Quasar 应用程序。现在,您可以从 Quasar 应用程序触发内容脚本可以监听的其他事件,并与底层页面进行交互。

警告

请务必检查您的清单文件,特别是 my-content-script.js 的引用。请注意,**您可以有多个内容脚本**。每当您创建一个新的内容脚本时,都需要在清单文件中引用它,并在 quasar.config 文件的 bex.contentScripts 部分中引用它。