orange
orange

Reputation: 8090

Define and reuse inline component in Vue3

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

Answers (3)

Kalnode
Kalnode

Reputation: 11306

Vue3: Use 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

Farid
Farid

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

Konrad
Konrad

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

Related Questions