您可以try 直接使用它,而不是包装传入的组件:
const defineCustomElement = (component, { plugins = [] } = {}) =>
VueDefineCustomElement({
...component,
setup(...args) {
const app = createApp({})
plugins.forEach(app.use)
const instance = getCurrentInstance()
Object.assign(instance.appContext, app._context)
Object.assign(instance.provides, app._context.provides)
return component.setup?.(...args)
},
})
见playground
在被覆盖的defineCustomElement()
函数中包装组件时,需要传递props 和emits ,然后将它们连接到组件实例:
const defineCustomElement = (component, { plugins = [] } = {}) =>
VueDefineCustomElement({
props: component.props, // <---- pass on component props
emits: component.emits, // <---- pass on component emits
setup(props, {emit}) {
const app = createApp({})
plugins.forEach(app.use)
const instance = getCurrentInstance()
Object.assign(instance.appContext, app._context)
Object.assign(instance.provides, app._context.provides)
const emitProps = turnEventNamesToProps(component.emits, emit) // <--- turn events into props (see below)
return () => h(component, {...props, ...emitProps}) // <--- return render function from setup
},
})
若要将emits 传递给实例,必须将它们转换为props .例如,如果您的组件发出一个名为myEvent
的事件,则需要传入一个带有处理程序的属性onMyEvent
,该处理程序在包装组件上触发发出.
下面是一个示例,它将事件名称数组转换为以属性名称为键、以处理程序为值的对象:
const emitEventToProp = eventName => 'on' + eventName[0].toUpperCase() + eventName.slice(1)
const turnEventNamesToProps = (eventNames, emitter) => {
const buildHandler = (eventName) => (...args) => emitter(eventName, ...params)
const entries = eventNames.map(eventName => [
emitEventToProp(eventName),
buildHandler(eventName)
])
return Object.fromEntries(entries)
}
请注意,Vue在Web组件上可以监听的事件名称似乎受到限制.虽然Web组件可以发出update:modelValue
事件,甚至还会发出update:model-value
事件,但在Vue模板中将@update:modelValue
放在Web组件上似乎不会注册侦听器.
这是一张playground元的