Vue 3 将组件附加到 DOM:最佳实践

Gen*_*ich 12 javascript vue.js vuejs3

我想在 SFC 中的 Vue 3 应用程序中动态创建一个组件,并将其附加到 DOM。我正在使用<script setup>样式组件,这是另一个问题。

这似乎不必要地困难。

这或多或少是我想做的:

  1. 获取一些数据。了解。
  2. 创建我的 Vue 组件的实例:Foo.vue。
  3. 将数据作为道具交给它。
  4. 将其附加到 DOM 中我想要的位置。

问题是我无法在模板中执行 <component :is="Foo:> 因为我不知道它会在哪里,直到模板渲染后很长时间。

这有最佳实践吗?某个善良的灵魂可以提供一个简单的例子,我们将不胜感激。

我有一半时间无法从 Vue 文档中弄清楚。抱歉,我不想这么说,但它们对于 Vue 新手来说相当不透明,让我觉得很愚蠢。

这是一些假装代码,说明了我想要做什么

import Foo from "../components/Foo.vue"

function makeAFoo(p, data){
// instantiate my Foo.vue (not sure how to do this inline), and pass it the data it needs
let foo = new Foo(data); // if only it were this simple, right?
// Append it to p (which is an HTML Element)
p.appendChild(foo)
}
Run Code Online (Sandbox Code Playgroud)

ton*_*y19 27

选项 1:createVNode(component, props)render(vnode, container)

创建:用于使用propscreateVNode()创建VNode组件定义(例如,从 导入的 SFC ),可以将其传递到给定容器元素上进行渲染。*.vuerender()

销毁:调用render(null, container) 会销毁VNode附加到容器的内容。unmounted当父组件卸载时(通过生命周期钩子) ,这应该被称为清理。

// renderComponent.js
import { createVNode, render } from 'vue'

export default function renderComponent({ el, component, props, appContext }) {
  let vnode = createVNode(component, props)
  vnode.appContext = { ...appContext }
  render(vnode, el)

  return () => {
    // destroy vnode
    render(null, el)
    vnode = undefined
  }
}
Run Code Online (Sandbox Code Playgroud)

警告:此方法依赖于内部方法 (createVNoderender),这些方法可能会在未来版本中重构或删除。

演示1

选项 2:createApp(component, props)app.mount(container)

创建:使用createApp(),返回一个应用程序实例。该实例具有mount(),可用于在给定容器元素上呈现组件。

销毁:应用程序实例必须unmount()销毁应用程序和组件实例。unmounted当父组件卸载时(通过生命周期钩子) ,这应该被称为清理。

// renderComponent.js
import { createApp } from 'vue'

export default function renderComponent({ el, component, props, appContext }) {
  let app = createApp(component, props)
  Object.assign(app._context, appContext) // must use Object.assign on _context
  app.mount(el)

  return () => {
    // destroy app/component
    app?.unmount()
    app = undefined
  }
}
Run Code Online (Sandbox Code Playgroud)

警告:此方法为每个组件创建一个应用程序实例,如果需要在文档中同时实例化许多组件,这可能是不小的开销。

演示2

用法示例

<script setup>
import { ref, onUnmounted, getCurrentInstance } from 'vue'
import renderComponent from './renderComponent'

const { appContext } = getCurrentInstance()
const container = ref()
let counter = 1
let destroyComp = null

onUnmounted(() => destroyComp?.())

const insert = async () => {
  destroyComp?.()
  destroyComp = renderComponent({
    el: container.value,
    component: (await import('@/components/HelloWorld.vue')).default
    props: {
      key: counter,
      msg: 'Message ' + counter++,
    },
    appContext,
  })
}
</script>

<template>
  <button @click="insert">Insert component</button>
  <div ref="container"></div>
</template>
Run Code Online (Sandbox Code Playgroud)