菜单

自定义元素

相关源文件

本页介绍了 Vue 对自定义元素(Web Components)的实现,以及如何将 Vue 组件转换为原生 Web Component。Vue 中的自定义元素允许您在标准 HTML 中使用 Vue 的响应式系统和组件模型,从而实现与其他框架或原生 JavaScript 应用程序的互操作性。

有关特定组件功能的更多信息,请参阅组件系统

概述

Vue 自定义元素是由 Vue 组件系统驱动的原生浏览器自定义元素。它们将 Vue 的响应式和组件模型与 Web Components 标准集成,允许 Vue 组件在任何 Web 应用程序中使用,无论其框架如何。

来源: packages/runtime-dom/src/apiCustomElement.ts63-184 packages/runtime-dom/src/index.ts253-262

API

Vue 提供了几个用于处理自定义元素的 API

API描述
defineCustomElement将 Vue 组件转换为自定义元素构造函数
defineSSRCustomElement创建用于 SSR 水化的自定义元素构造函数
VueElementVue 驱动的自定义元素基类
useHost组件钩子,用于访问自定义元素实例
useShadowRoot组件钩子,用于访问自定义元素的 shadow root

来源: packages/runtime-dom/src/apiCustomElement.ts64-184 packages/runtime-dom/src/apiCustomElement.ts685-712

定义自定义元素

defineCustomElement 函数将 Vue 组件定义转换为自定义元素构造函数。它接受与 defineComponent 相同的选项,以及额外的自定义元素特定选项。

来源: packages/runtime-dom/src/apiCustomElement.ts53-58 packages/runtime-dom/src/apiCustomElement.ts167-185

使用示例

  1. 定义自定义元素
  1. 在 HTML 中使用它

来源: packages/runtime-dom/__tests__/customElement.spec.ts34-46

架构

VueElement 实现

VueElement 类是 Vue 自定义元素实现的基础。它扩展了 HTMLElement,并管理自定义元素内的 Vue 组件生命周期。

来源: packages/runtime-dom/src/apiCustomElement.ts202-683

生命周期集成

自定义元素的生命周期钩子映射到 Vue 组件的生命周期如下

  1. 初始化:

    • 自定义元素已创建 → Vue 组件尚未初始化
    • 在自定义元素上设置的 props 会在挂载前被存储
  2. 连接:

    • connectedCallback → 创建并挂载 Vue 组件
    • 解析组件定义(处理异步组件)
    • 设置属性和特性
  3. 更新:

    • 特性更改 → 更新 Vue 组件 props
    • Vue 组件更新 → 更改反映在 shadow DOM 中
  4. 断开连接:

    • disconnectedCallback → 卸载 Vue 组件
    • 清理资源

来源: packages/runtime-dom/src/apiCustomElement.ts279-337 packages/runtime-dom/src/apiCustomElement.ts466-520

属性和特性

Vue 自定义元素会自动在组件 props 和 DOM 属性之间同步

  1. 组件 props 作为自定义元素的属性暴露
  2. 连字符分隔的属性(例如 my-prop)映射到 camelCase 属性(例如 myProp
  3. 原始 prop 值会反映到属性
  4. 对象/数组 props 可作为属性访问,但不会反映为属性
  5. 类型转换会自动进行(字符串属性 → 类型化的 props)

来源: packages/runtime-dom/src/apiCustomElement.ts442-463 packages/runtime-dom/src/apiCustomElement.ts487-520 packages/runtime-dom/__tests__/customElement.spec.ts150-238

事件

从 Vue 组件发出的事件会被调度为原生的 DOM CustomEvents

  1. 组件使用 emit 发出事件
  2. 自定义元素调度一个同名的 CustomEvent
  3. 对于 camelCase 事件,会同时调度原始事件名和 kebab-case 形式的事件名
  4. 事件数据包含在 CustomEvent 的 detail 属性中

来源: packages/runtime-dom/src/apiCustomElement.ts552-571 packages/runtime-dom/__tests__/customElement.spec.ts476-584

Slots 和 Shadow DOM

Vue 自定义元素默认支持原生 shadow DOM slots

  1. 默认行为是以 open 模式创建 shadow root
  2. 组件模板使用 <slot> 元素,映射到原生 slots
  3. 内容分布遵循标准的 shadow DOM 规则

可以通过将 shadowRoot 选项设置为 false 来禁用 shadow DOM 的使用。在这种情况下:

  1. 组件直接渲染到自定义元素中
  2. Slots 由 Vue 手动管理
  3. 样式不自动应用(无 shadow DOM 隔离)

来源: packages/runtime-dom/src/apiCustomElement.ts264-271 packages/runtime-dom/src/apiCustomElement.ts617-657 packages/runtime-dom/__tests__/customElement.spec.ts588-664 packages/runtime-dom/__tests__/customElement.spec.ts957-1025

样式

组件中定义的样式将被注入到 shadow DOM 中

  1. 组件可以通过 styles 数组选项定义样式
  2. 样式将作为 <style> 元素注入到 shadow root 中
  3. 支持 HMR,可在开发过程中实时更新样式
  4. 子组件的样式也会被注入

可以使用 nonce 选项配合 nonce 值来应用样式,以兼容内容安全策略 (CSP)。

来源: packages/runtime-dom/src/apiCustomElement.ts579-612 packages/runtime-dom/__tests__/customElement.spec.ts714-809

高级特性

服务器端渲染 (SSR)

Vue 支持自定义元素的 SSR

  1. 使用 defineSSRCustomElement 代替 defineCustomElement
  2. 与声明式 Shadow DOM 配合使用,实现无缝水化
  3. 客户端在不重新渲染的情况下水化服务器渲染的 HTML

来源: packages/runtime-dom/src/apiCustomElement.ts188-194 packages/vue/__tests__/e2e/ssr-custom-element.spec.ts18-79

异步组件

自定义元素可以与异步组件一起定义

  1. 组件定义异步加载
  2. 加载前设置的属性会被保留
  3. 组件加载完成后,元素才会渲染

来源: packages/runtime-dom/src/apiCustomElement.ts404-411 packages/runtime-dom/__tests__/customElement.spec.ts812-904

提供/注入 (Provide/Inject)

自定义元素支持 Vue 的 provide/inject 功能

  1. 父级自定义元素可以向子级自定义元素提供值
  2. 跨 Shadow DOM 边界工作
  3. 保持响应性

来源: packages/runtime-dom/src/apiCustomElement.ts316-321 packages/runtime-dom/__tests__/customElement.spec.ts614-710

热模块替换(HMR)

自定义元素支持 HMR (热模块替换) 用于开发

  1. 组件更新在不进行页面完全重载的情况下应用
  2. 状态在更新过程中得以保留
  3. 样式可以独立更新

来源: packages/runtime-dom/src/apiCustomElement.ts539-551 packages/runtime-core/src/hmr.ts137-141

与其他框架的集成

Vue 自定义元素的主要优势之一是框架互操作性

框架用途
原生 JavaScriptdocument.createElement('my-element')
React<my-element message="hello" />
Angular<my-element [message]="data" />
Svelte<my-element message={data} />
Vue<my-element :message="data" />

在非 Vue 应用中使用 Vue 自定义元素时

  1. 仅包含组件代码(全局作用域中没有 Vue 运行时)
  2. Props 通过标准的 HTML 属性和属性工作
  3. Events 遵循标准的 DOM 事件模式
  4. 不需要 Vue 特定的功能,例如指令

局限性

虽然 Vue 自定义元素提供了丰富的功能,但也存在一些限制

  1. 不支持直接使用指令(必须将其转换为 props 或渲染函数)
  2. 像 `<Transition>` 这样的某些 Vue 特有功能需要特殊处理
  3. 服务器端渲染需要声明式 Shadow DOM 支持或 polyfills
  4. 使用 `shadowRoot: false` 时,组件样式不会被应用

来源: packages/runtime-dom/src/apiCustomElement.ts393-397