Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add Vue 3 components programmatically?

Vue 3 doesn't have Vue.extend() method, so example here doesn't work: https://css-tricks.com/creating-vue-js-component-instances-programmatically/

I have tried this solution: https://jsfiddle.net/jamesbrndwgn/fsoe7cuy/

But it causes warning in console:

Vue received a Component which was made a reactive object. This can lead to unnecessary performance overhead, and should be avoided by marking the component with markRaw or using shallowRef instead of ref.

enter image description here

So, what is the proper way to add components dynamically (programmatically) in Vue 3?

UploadTaskTagManager.vue

<template>
    <button @click="addTag()" type="button">Add new tag</button>
    <br>
    <div>
        <div v-for="child in children" :key="child.name">
            <component :is="child"></component>
        </div>
    </div>
</template>

<script>
    import UploadTaskTag from "./UploadTaskTag";

    export default {
        name: "UploadTaskTagManager",
        components: {UploadTaskTag},

        data() {
            return {
                children: []
            }
        },

        methods: {
            addTag() {
                this.children.push(UploadTaskTag);
            },
        }
    }
</script>

UploadTaskTag.vue

<template>
    <div>
        <select @change="onChangeTag($event)" v-model="currentTag">
            <option v-for="tag in getAllTags()" :key="tag.tag_name" :value="tag">{{tag.tag_name}}</option>
        </select>
        <input maxlength="16" class="tag-input" ref="inputField"/>
        <button @click="removeTag($event)" type="button">-</button>
        <br>
    </div>
</template>

<script>
    export default {
        name: "UploadTaskTag",

        data() {
            return {
                tags: [],
                currentTag: {}
            }
        },

        methods: {
            onChangeTag(event) {
                this.$refs.inputField.value = this.currentTag.tag_name;
            },

            getAllTags() {
                return this.$store.state.allTags;
            },

            removeTag() {
                this.$el.parentElement.removeChild(this.$el)
            },

            getValue(fieldIndex) {
                let tag = this.tags[fieldIndex];
                return tag ? tag.tag_name : "";
            },
        }
    }
</script>
like image 562
Gradess Avatar asked Feb 12 '21 10:02

Gradess


People also ask

How do I add components to vue3?

To use a component in another component, follow the below steps: Import the . vue file into the component script tag. Add the default export to the component property.

How do I add components to Vue?

Open the file in your code editor. Create the component's template section by adding <template></template> to the top of the file. Create a <script></script> section below your template section. Inside the <script> tags, add a default exported object export default {} , which is your component object.

Can I use Vue 3 without composition API?

Find answer to this question in the following article and discover the benefits of Composition API. Vue 3 introduced a new approach to creating components called Composition API . It is an alternative to the Options API . The Composition API is fully optional and you don't need to use it if you want to use Vue 3.


2 Answers

just use createApp instead of Vue.extend here's a example of simple vue3 components programmatically

import Button from 'Button.vue'
import { createApp } from "vue"
// Creating the Instance
// use createApp https://v3.vuejs.org/api/global-api.html#createapp
var ComponentApp = createApp(Button)
import Button from "./Button.vue"

// inserting to dom
const wrapper = document.createElement("div")
ComponentApp.mount(wrapper)
document.body.appendChild(wrapper)

set props or slot is a little different by use h, https://v3.vuejs.org/api/global-api.html#h

import Button from 'Button.vue'
import { createApp, h } from "vue"

var ComponentApp = createApp({ 
  setup () {
    return () => h(Button, {type: "primary"}, "default slot as children")
  }
})
like image 145
ethan_you Avatar answered Oct 17 '22 23:10

ethan_you


If I understood you correctly, then the solution will be like this

You can learn more about 'defineAsyncComponent' on the official website https://v3.vuejs.org/api/global-api.html#defineasynccomponent

<template>
    <button @click="addTag()" type="button">Add new tag</button>
    <br>
    <div>
        <div v-for="child in children" :key="child.name">
            <component :is="child"></component>
        </div>
    </div>
</template>

<script>

import { defineAsyncComponent, defineComponent, ref } from "vue"

export default defineComponent({
components: {     
      UploadTaskTag: defineAsyncComponent(() => import("./UploadTaskTag"))
    },
 setup() {
      const children = ref([])

      const addTag = () => {
        children.value.push('UploadTaskTag')
        console.log(children.value)
      }
return {
        addTag,
        children        
      }
    },
  })
</script>
like image 5
Oleksii Zelenko Avatar answered Oct 17 '22 23:10

Oleksii Zelenko