Plasmo CSUI 的生命周期

447 阅读4分钟

原文链接:docs.plasmo.com/framework/c…

本文为官网翻译,因感觉AI翻译晦涩难懂,在学习过程中进行翻译总结。

Plasmo 的 CSUI(Content Script UI)定义了一套生命周期体系,用于在内容脚本中挂载和卸载 React、Vue 或 Svelte 组件。尽管每个 UI 库/框架挂载 API都有稍微的不同,但顶层生命周期在很大程度上是相同的。

  1. 获取锚点Anchor
  2. 创建或定位一个Root Container
  3. 将组件渲染到Root Container上。

术语

术语
Anchor告诉 CSUI 如何以及在哪里挂载你的组件。
Anchor-getter告诉 CSUI 如何找到Anchor
Overlay将组件挂载到顶层覆盖型元素(z-index最大)上。
Inline将组件挂载到网页的 DOM 中,放置在目标元素旁边。
Root ContainerCSUI创建的用于隔离你的组件的 ShadowDOM 元素。

Anchor

image.png

Plasmo CSUI的Anchor由以下类型定义:

export type PlasmoCSUIAnchor = {
  type: "overlay" | "inline"
  element: Element
}

默认情况下,CSUI 生命周期使用document.body元素创建一个覆盖型锚点:

{
  type: "overlay",
  element: document.body
}

如果定义并导出了任何anchor-getter函数,CSUI 生命周期将使用返回的元素和对应的Anchor类型。由于anchor-getter函数可以是异步的,因此你也可以控制 Plasmo 挂载你的组件的时机。例如,你可以等待特定元素出现在页面上,然后再挂载你的组件。

anchor通过anchor 属性传递给 CSUI。您可以像这样访问它:

import type { PlasmoCSUIProps } from "plasmo"
 
const AnchorTypePrinter: FC<PlasmoCSUIProps> = ({ anchor }) => {
  return <span>{anchor.type}</span>
}
 
export default AnchorTypePrinter

Overlay

覆盖型的anchor会生成CSUI覆盖型容器,每份 CSUI 的覆盖型容器会批量挂载到单个Root Container元素上。覆盖型容器相对于每个anchor元素进行绝对定位,并具有最大的z-index。然后,你导出的CSUI Component会挂载到每个覆盖型容器上。

image.png

如果要指定单个覆盖型锚点,需要导出一个getOverlayAnchor函数:

import type { PlasmoGetOverlayAnchor } from "plasmo"
 
export const getOverlayAnchor: PlasmoGetOverlayAnchor = async () =>
  document.querySelector("#pricing")

如果要指定覆盖型锚点列表,需要导出一个getOverlayAnchorList函数:

import type { PlasmoGetOverlayAnchorList } from "plasmo"
 
export const getOverlayAnchorList: PlasmoGetOverlayAnchorList = async () =>
  document.querySelectorAll("a")

⚠️ getOverlayAnchorList目前没有涵盖动态情况。例如,如果在初始渲染后向网页添加新的锚点,CSUI lifecycle 将无法检测到它。欢迎提交 PR 以改进此功能!

更新位置

默认的覆盖型容器监听窗口滚动事件以使其自身与锚点元素对齐。你可以通过导出一个watchOverlayAnchor函数来自定义覆盖型容器更新其绝对定位的方式。下面的例子每隔 8472 毫秒刷新一次位置。

import type { PlasmoWatchOverlayAnchor } from "plasmo"
 
export const watchOverlayAnchor: PlasmoWatchOverlayAnchor = (
  updatePosition
) => {
  const interval = setInterval(() => {
    updatePosition()
  }, 8472)
 
  // Clear the interval when unmounted
  return () => {
    clearInterval(interval)
  }
}

点击with-content-scripts-ui/contents/plasmo-overlay-watch.tsx以获取示例。

Inline

内联型锚点将CSUI Component直接嵌入到网页中,每个锚点都会在其目标元素旁边派生出一个Root Container。在每个Root Container中,会创建一个Inline Container,然后该内联容器用于挂载导出的CSUI Component

image.png

指定单个内联型锚点,需要导出一个getInlineAnchor函数:

import type { PlasmoGetInlineAnchor } from "plasmo"
 
export const getInlineAnchor: PlasmoGetInlineAnchor = async () =>
  document.querySelector("#pricing")

如果需要在指定单个内联型锚点时同时指定位置,可以这样做:

import type { PlasmoGetInlineAnchor } from "plasmo"
 
export const getInlineAnchor: PlasmoGetInlineAnchor = async () => ({
      element: document.querySelector("#pricing"),
      insertPosition: "afterend"
})

如果要指定内联型锚点列表,可以导出一个getInlineAnchorList函数:

import type { PlasmoGetInlineAnchorList } from "plasmo"
 
export const getInlineAnchorList: PlasmoGetInlineAnchorList = async () =>
  document.querySelectorAll("a")

如果要指定具有插入位置的内联锚点列表:

import type { PlasmoGetInlineAnchorList } from "plasmo"
 
export const getInlineAnchorList: PlasmoGetInlineAnchorList = async () => {
  const anchors = document.querySelectorAll("a")
  return Array.from(anchors).map((element) => ({
    element,
    insertPosition: "afterend"
  }))
}

点击with-content-scripts-ui/contents/plasmo-inline.tsx以获取示例。

Root Container

image.png

Root Container是挂载CSUI Component的位置,内置的Root Container是一个带有plasmo-csui自定义标签的 ShadowDOM 元素。这使得你可以对Root Container及其导出的组件进行样式设置,而不会受到当前宿主网页样式的影响。

自定义 DOM 挂载

Root Container创建一个shadowHost(影子宿主),该影子宿主被注入到网页的 DOM 树中。默认情况下,Plasmo 在内联型锚点的元素之后以及覆盖型锚点的document.body之前注入shadowHost。要自定义此行为,请导出一个mountShadowHost函数。