阿里云主机折上折
  • 微信号
Current Site:Index > The support method for custom elements

The support method for custom elements

Author:Chuan Chen 阅读数:11789人阅读 分类: Vue.js

Support for Custom Elements

Vue 3 has significantly improved its support for custom elements, primarily reflected at both compile-time and runtime levels. This enhancement allows developers to interoperate more naturally with Web Components or custom elements from other frameworks.

Compile-Time Handling

The Vue 3 compiler identifies custom elements through the isCustomElement option. When encountering non-native HTML tags, the compiler checks whether the tag is marked as a custom element:

// vite.config.js
import vue from '@vitejs/plugin-vue'

export default {
  plugins: [
    vue({
      template: {
        compilerOptions: {
          isCustomElement: tag => tag.startsWith('my-')
        }
      }
    })
  ]
}

This configuration tells the compiler that all tags starting with my- should be treated as custom elements, and Vue will not attempt to parse them as Vue components. The compiled code retains the original tag names and attributes of these custom elements.

Runtime Behavior

At runtime, Vue continues to support custom elements through the config.isCustomElement configuration:

const app = createApp(App)
app.config.isCustomElement = tag => tag.startsWith('ion-')

This runtime check ensures Vue does not attempt to resolve or patch these elements. Custom elements are passed directly to the browser for processing, with Vue only managing their attributes and events.

Attribute Passing Mechanism

Vue handles custom element attributes in three modes:

  1. Automatic Mode: Vue automatically detects attribute types.
<my-element :user.prop="{ name: 'John' }"></my-element>
  1. Explicit Declaration: Forces treatment as a property using the .prop modifier.
<my-element :someProp.prop="value"></my-element>
  1. Attribute Fallback: Falls back to attributes if property setting fails.
<my-element :some-attr="value"></my-element>

Event System Integration

Custom element events can be listened to like native events:

<my-element @custom-event="handleEvent"></my-element>

Vue automatically converts events to lowercase for matching, consistent with native DOM event behavior. For custom event objects, data can be accessed via $event:

methods: {
  handleEvent(event) {
    console.log(event.detail) // Access custom event data
  }
}

Mixing with Vue Components

Custom elements can be freely combined with Vue components:

<template>
  <div>
    <my-custom-element>
      <vue-component :prop="data"/>
    </my-custom-element>
  </div>
</template>

Vue correctly handles slot content, even when projected into the custom element's Shadow DOM.

Lifecycle Coordination

Vue ensures custom element lifecycles work in harmony with Vue components. When a custom element is wrapped by a Vue component:

customElements.define('my-element', class extends HTMLElement {
  connectedCallback() {
    // Triggered when the element is inserted into the DOM
  }
  disconnectedCallback() {
    // Triggered when the element is removed from the DOM
  }
})

Vue's mount and unmount operations correctly trigger these callbacks.

Style Encapsulation Handling

For custom elements using Shadow DOM, Vue provides special style processing:

<style>
  :host {
    display: block;
  }
</style>

<template>
  <my-element></my-element>
</template>

Vue does not attempt to inject scoped styles into the Shadow DOM, but styles can pierce the Shadow DOM boundary using ::v-deep:

::v-deep my-element::part(inner) {
  color: red;
}

Form Element Integration

Custom form elements can integrate with v-model:

<my-input v-model="text"></my-input>

The custom element must implement the standard value property and input event:

class MyInput extends HTMLElement {
  get value() { /* ... */ }
  set value(v) { /* ... */ }
}

Performance Optimization Strategies

Vue implements several optimizations for custom element handling:

  1. Skipping unnecessary reactivity conversion: Custom element properties are not converted to reactive properties.
  2. Reducing patch operations: Vue skips virtual DOM diffing for custom elements.
  3. Event listener caching: Event listeners of the same type are reused.

Testing Custom Elements

In test environments, configure Vue Test Utils to recognize custom elements:

import { config } from '@vue/test-utils'

config.global.config = {
  isCustomElement: tag => tag.startsWith('my-')
}

This ensures custom elements are processed correctly during testing.

Integration with Third-Party Libraries

When using libraries like Lit or Stencil, special attention is required:

import { defineCustomElement } from 'vue'

const MyVueElement = defineCustomElement({
  // Normal Vue component options
})

customElements.define('my-vue-element', MyVueElement)

This pattern allows exporting Vue components as custom elements, enabling two-way interoperability.

Browser Compatibility Considerations

Vue 3's custom element support must account for implementation differences across browsers:

app.config.isCustomElement = tag => {
  // Special handling for older browsers
  if (typeof customElements !== 'undefined') {
    return customElements.get(tag) !== undefined
  }
  return false
}

Server-Side Rendering Support

For SSR scenarios, custom elements require special handling:

import { renderToString } from '@vue/server-renderer'

const html = await renderToString(app, {
  isCustomElement: tag => tag.includes('-')
})

The server outputs custom element tags as-is, and client-side hydration correctly matches them.

Type System Integration

For TypeScript projects, global types can be extended:

declare global {
  namespace JSX {
    interface IntrinsicElements {
      'my-element': React.DetailedHTMLProps<
        React.HTMLAttributes<HTMLElement>,
        HTMLElement
      > & {
        someProp?: string
      }
    }
  }
}

This provides type checking and autocompletion in templates.

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.