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
propsinto the wrapper'sprops:Move the wrapper's
renderprop into a return fromsetup().Pass
setup()'spropsargument to the rendering ofApp(h()receivespropsas 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️⃣)
}
})
