【问题标题】:Vue 3 Append Component to the DOM: Best PracticeVue 3 将组件附加到 DOM:最佳实践
【发布时间】:2021-10-07 21:53:19
【问题描述】:

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

这似乎是不必要的困难。

这或多或少是我想做的事情:

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

问题是我不能在模板中做

【问题讨论】:

标签: javascript vue.js vuejs3


【解决方案1】:

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

创建: 使用 createVNode() 来创建带有 props 的组件定义的 VNode(例如,从 *.vue 导入的 SFC),可以将其传递给 render() 以进行渲染在给定的容器元素上。

销毁:调用附加到容器的render(null, container) destroys the VNode。当父组件卸载(通过unmounted lifecycle hook)时,这应该被称为清理。

// 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
  }
}

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

demo 1

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

创建:使用createApp(),它返回一个application instance。该实例有mount(),可用于在给定容器elemenet上渲染组件。

销毁:应用实例有unmount()来销毁应用和组件实例。当父组件卸载(通过unmounted lifecycle hook)时,这应该被称为清理。

// 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
  }
}

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

demo 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>

【讨论】:

  • render创建的动态组件目前无法被VueDevtools v6.0.0-beta.20检查。
猜你喜欢
  • 2023-02-02
  • 2012-10-12
  • 1970-01-01
  • 2018-12-24
  • 2021-07-03
  • 2022-09-28
  • 2020-02-10
  • 2015-08-21
  • 1970-01-01
相关资源
最近更新 更多