如何以编程方式添加 Vue 3 组件?

Gra*_*ess 2 vue.js vue-component vuejs3

Vue 3 没有 Vue.extend() 方法,所以这里的例子不起作用:https ://css-tricks.com/creating-vue-js-component-instances-programmatically/

我试过这个解决方案:https : //jsfiddle.net/jamesbrndwgn/fsoe7cuy/

但它会在控制台中引起警告:

Vue 收到了一个组件,它是一个响应式对象。这会导致不必要的性能开销,应该通过用markRawshallowRef代替标记组件来避免ref

在此处输入图片说明

那么,在 Vue 3 中动态(以编程方式)添加组件的正确方法是什么?

上传任务标签管理器.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>
Run Code Online (Sandbox Code Playgroud)

上传任务标签.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>
Run Code Online (Sandbox Code Playgroud)

Ole*_*nko 8

如果我理解正确的话,那么解决方案将是这样的

您可以在官方网站上了解有关“defineAsyncComponent”的更多信息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>
Run Code Online (Sandbox Code Playgroud)


小智 5

只是使用createApp而不是Vue.extend 这里的一个简单的 vue3 组件的编程示例

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)
Run Code Online (Sandbox Code Playgroud)

set props or slot 在使用上有点不同hhttps://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")
  }
})
Run Code Online (Sandbox Code Playgroud)

  • 不知怎的,使用 createApp() 以编程方式添加一个小的 Vue 组件感觉是错误的。它让我想起了臃肿和开销的景象。不过我必须把它交给你,你的回答很有效。 (15认同)
  • 我面临着类似的问题。我只想动态创建一个组件并将其附加到 Vue 3 中的 DOM,这似乎不必要地困难。为什么要创建一个新的 Vue 实例?我不明白这一点。难道就没有更简单的办法吗? (4认同)
  • 我对这个解决方案的唯一问题是,您失去了主应用程序所具有的任何范围...例如,如果您有全局变量或提供的项目等。否则,这个答案正是如此。 (2认同)