Reputation: 8090
Is it possible to define a "sub component" inline in Vue3 which can be reused in the same .vue file/component, but without actually defining a new .vue
file (i.e. without defining this sub component as a new component).
The use case is that I have a very specific way of formatting <select>
options which is used for multiple <select>
s within the same component (.vue
file), but which will not be used anywhere else (it's also small, so I am inclined to define this options formatting part inline). I don't necessarily want to copy and paste the formatting (and it would be good to keep it within the same .vue file because it's small).
I realise that this is only syntactic sugar which may or may not be relevant in specific cases (I'm also not seeking advice on whether or not this is a good idea). I'm just looking for a way this can be done (if not, that's also an answer ;-))
Upvotes: 4
Views: 4878
Reputation: 11306
defineComponent
Vue3 provides defineComponent which is probably what you want to consider for inline components. The docs for this could be deeper; I would seek out more tutorials and discussions on defineComponent.
You probably also want to understand rendering with h()
. There are so many ways to use it! https://vuejs.org/guide/extras/render-function
Alternative: Regarding the render function, Vue3 has something called Functional Component
which may be better for very simple inline components: https://vuejs.org/guide/extras/render-function#functional-components
In any case, here's one working implementation of defineComponent
(code is Composition API + Typescript).
Example
<script setup lang="ts">
//...
const myInlineComponent = defineComponent(
(props) => {
// Use Composition API here, like in <script setup>
// e.g. const count = ref(0)
// Must return something, which ultimately is the vnode output
return () => {
// Use h() render function...
//e.g. return h('div', { class: `myClass` }, () => 'Some String')
// or JSX...
//e.g. return <div>{count.value}</div>
// Example using render function h():
return h(
Button,
{
onClick: (e:any) => {
console.log('Button clicked: ', props.someProp)
},
class: {
"myClass": true
}
},
() => 'Some String'
)
}
},
{
props: {
someProp: { type: string, required: true }
}
}
)
//...
</script>
Then use in a template
<myInlineComponent :someProp="'someString'" />
Upvotes: 1
Reputation: 463
You can define h()
function to create vnodes inside your setup
script in vue 3.
for example:
<template>
<MyComponent />
</template>
<script setup>
const MyComponent = h('div', { class: 'bar', innerHTML: 'hello' })
</script>
vue document will help you completely. document
Upvotes: 2
Reputation: 24661
You could do something like this in Vue2
Vue.component('my-checkbox', {
template: '<div class="checkbox-wrapper" @click="check"><div :class="{ checkbox: true, checked: checked }"></div><div class="title">{{ title }}</div></div>',
data() {
return { checked: false, title: 'Check me' }
},
methods: {
check() { this.checked = !this.checked; }
}
});
Probably still works
Upvotes: 1