I use new future defineCustomElement from vue version 3.2.
Code main.js
:
import { defineCustomElement } from './defineCustomElementWithStyles'
import App from './App.ce.vue'
import store from './store'
import router from './router'
customElements.define(
'app-root',
defineCustomElement(App, {
plugins: [store, router],
})
)
Code defineCustomElementWithStyles.js
:
import { defineCustomElement as VueDefineCustomElement, h, createApp, getCurrentInstance } from 'vue'
const getNearestElementParent = (el) => {
while (el?.nodeType !== 1 /* ELEMENT */) {
el = el.parentElement
}
return el
}
export const defineCustomElement = (component, { plugins = [] }) =>
VueDefineCustomElement({
render: () => h(component),
setup() {
const app = createApp()
// install plugins
plugins.forEach(app.use)
app.mixin({
mounted() {
const insertStyles = (styles) => {
if (styles?.length) {
this.__style = document.createElement('style')
this.__style.innerText = styles.join().replace(/\n/g, '')
getNearestElementParent(this.$el).prepend(this.__style)
}
}
// load own styles
insertStyles(this.$?.type.styles)
// load styles of child components
if (this.$options.components) {
for (const comp of Object.values(this.$options.components)) {
insertStyles(comp.styles)
}
}
},
unmounted() {
this.__style?.remove()
},
})
const inst = getCurrentInstance()
Object.assign(inst.appContext, app._context)
Object.assign(inst.provides, app._context.provides)
},
})
Code App.ce.vue
where I register and use prop
:
<template>
<div id="app">
<p>{{ title }}</p>
<nav>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<main>
<router-view />
</main>
</div>
</template>
<script>
export default {
name: 'App',
props: {
title: String,
},
}
</script>
Code index.html
where I set value fro prop title
:
<app-root title="hello"></app-root>
Get error with message:
Uncaught TypeError: Cannot read properties of undefined (reading 'title')
Full demo project here
CodePudding user response:
Since the App
component is being wrapped in defineCustomElementWithStyle
, the wrapper's props
should be passed to App
within setup()
.
Copy the component's
props
into the wrapper'sprops
:Move the wrapper's
render
prop into a return fromsetup()
.Pass
setup()
'sprops
argument to the rendering ofApp
(h()
receivesprops
as its 2nd argument).
export const defineCustomElement = (component, { plugins = [] }) =>
VueDefineCustomElement({
props: component.props, 1️⃣
// render: () => h(component), 2️⃣
setup(props 3️⃣) {
⋮
return () => h(component, props 3️⃣)
}
})