I am developing a dynamic dashboard in Vue 3 where the user can specify simple XML-like templates for the parts that they want to render.
I would like to have the nodes in the XML that match the name of specific Vue components rendered as Vue components, while the other nodes should be rendered as normal HTML.
For example, an XML template may look like this:
<Dashboard>
<Elements>
<div class="title">Switches</div>
<Switches device="kitchen-bulb" />
</Elements>
</Dashboard>
The <div> inside of <Elements> should be rendered as normal HTML (and I have achieved this already by both leveraging <slot> and passing the node content to v-html on the <Elements> component), while <Switches>, which matches the name of a specific imported Vue component, should be rendered as a Vue component - in this case with a device property passed from the template.
The code right now looks like this:
/// index.js
import Switch from './Switch'
export default {
Switch,
}
/// Elements.vue
<template>
<div class="elements">
<div class="container" v-html="content" />
</div>
</template>
<script>
import elements from './index'
export default {
name: "Elements",
props: {
content: {
type: String,
},
},
mounted() {
const content = new DOMParser()
.parseFromString(`<div>${this.content}</div>`, 'text/html')
.childNodes[0]
Object.entries(elements).forEach(([name, element]) => {
this.$options.components[name] = element
const nodes = content.getElementsByTagName(name);
[...nodes].forEach((node) => {
const renderedComponent = magicStringToRenderedHTMLStringOrDOM(element, node)
node.parentElement.replaceChild(renderedComponent, node)
})
})
this.content = content.childNodes[0].innerHTML
},
}
</script>
content is the node content of <Elements> passed to the component by its parent.
What I need is something to fill the magicStringToRenderedHTMLStringOrDOM call that, given the Vue component definition, the node representation and the properties, renders Vue component that I can simply replace in content and render with v-html.
I know that Vue 2 used to provide something similar with Vue.compile. The only Vue 3 function I have found that apparently does something similar is createRenderer, but I haven't found many examples of how to use it.