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", // 右键选项菜单
  "browser_action": {
    "default_popup": "www/index.html#/popup" // 弹窗
  },
  "devtools_page": "www/index.html#/devtools", // 开发者工具
}

manifest v3

{
  "manifest_version": 3,

  "action": {
    "default_popup": "www/index.html#/popup" // 弹窗
  },
  "options_page": "www/index.html#/options", // 右键选项菜单
  "devtools_page": "www/index.html#/devtools", // 开发者工具
}

Web 页面

真正厉害的是,我们可以使用一些简单的技巧,将 Quasar 应用注入到页面中,使其成为页面的一部分。

下面是一个简单的示例:

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

思路是创建一个 IFrame,并将我们的 Quasar 应用添加到其中,然后注入到网页中。

考虑到我们的 Quasar 应用可能会占据窗口的全部高度(从而阻挡与底层页面的任何交互),我们需要有一个事件来处理 IFrame 的高度设置。默认情况下,IFrame 高度刚好高到可以显示 Quasar 工具栏(进而允许与页面的其他部分交互)。

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

// 这里添加的钩子为 BEX 内容脚本和 Quasar 应用程序之间的通信搭建了一个桥梁。
// 更多信息: https://www.quasar-cn.cm/quasar-cli-vite/developing-browser-extensions/content-hooks

import { bexContent } from 'quasar/wrappers'

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

/**
 * 设置 iframe 容纳 BEX 的高度
 * @param height
 */
const setIFrameHeight = height => {
  iFrame.height = height
}

/**
 * 将 iframe 重置为默认高度,例如顶部栏的高度。
 */
const resetIFrameHeight = () => {
  setIFrameHeight(defaultFrameHeight)
}

/**
 * 下面的代码将使一切顺利进行。用默认设置初始化 iframe,然后将其添加到页面上
 * @type {string}
 */
iFrame.id = 'bex-app-iframe'
iFrame.width = '100%'
resetIFrameHeight()

// 应用一些样式,使其看起来更像一个整体
Object.assign(iFrame.style, {
  position: 'fixed',
  top: '0',
  right: '0',
  bottom: '0',
  left: '0',
  border: '0',
  zIndex: '9999999', // 确保它在最顶层
  overflow: 'visible'
})

;(function () {
  // 当页面加载时,插入我们的浏览器插件应用程序。
  iFrame.src = chrome.runtime.getURL(`www/index.html`)
  document.body.prepend(iFrame)
})()

export default function (bridge) {
  /**
   * 切换抽屉时,将 iFrame 高度设置为占据整个页面。
   * 当抽屉关闭时重置高度。
   */
  bridge.on('wb.drawer.toggle',  ({ data, respond }) => {
    if (data.open) {
      setIFrameHeight('100%')
    } else {
      resetIFrameHeight()
    }
    respond()
  })
}

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

  • src-bex/assets/content.css

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

.target-some-header-class {
  margin-top: 62px;
}
  • Quasar App (/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 // 所以它知道要变得更大 / 更小
      })

      // 只有在 Promise 解决后才设置此选项,这样我们才能看到整个幻灯片动画。
      drawerIsOpen.value = !drawerIsOpen.value
  }

  return { drawerToggled }
}

现在你有一个 Quasar 应用程序在网页上运行。您可以从 Quasar 应用程序触发其他事件,内容脚本可以侦听这些事件并与底层页面进行交互。

警告

一定要检查 manifest 文件,尤其是对 my-content-script.js 的引用。请注意,您可以拥有多个内容脚本。每当创建新的时,都需要在清单文件中引用它。