The support method for custom elements
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:
- Automatic Mode: Vue automatically detects attribute types.
<my-element :user.prop="{ name: 'John' }"></my-element>
- Explicit Declaration: Forces treatment as a property using the
.prop
modifier.
<my-element :someProp.prop="value"></my-element>
- 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:
- Skipping unnecessary reactivity conversion: Custom element properties are not converted to reactive properties.
- Reducing patch operations: Vue skips virtual DOM diffing for custom elements.
- 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
上一篇:组件事件系统的内部机制
下一篇:响应式系统的惰性求值