vue3如何动态把组件添加到dom中

开始

需求很简单,因为一些原因我并不想在template中直接使用子组件,
于是我想是否可以通过方法直接把组件插入到dom中呢?当然是可以的了~~

但是我又想偷懒,于是我想到element plus也是在一些组件中也在dom插入了组件。
于是我就默默的准备copy它的代码了~

第一步,确定哪个组件会有该功能(我想到了message)

第二步,找到该组件

在element plus中找到该组件位置
组件位置:packages/components/message/src
组件代码位置
我们看到message/index.ts是入口文件,message.vue应该就是组件的文件了

但是我们是动态插入该组件,那说明在dom中插入该组件的方法不在该文件中,所以先就不看它了。

然后我再打开methods.ts,首先看到了

import { createVNode, render } from 'vue'
...
import MessageConstructor from './message.vue'
...

这俩函数我就不多说了,看名字也知道是和创建元素节点和渲染有关的函数了

我们看到也引入了message.vue

这个时候我隐约猜到了,应该就是在这里插入了该组件,于是我搜索了一下createVNode和render方法

于是我找到了

const container = document.createElement('div')

  const props = {
    ...options,
    // now the zIndex will be used inside the message.vue component instead of here.
    // zIndex: nextIndex() + options.zIndex
    id,
    onClose: () => {
      userOnClose?.()
      closeMessage(instance)
    },

    // clean message element preventing mem leak
    onDestroy: () => {
      // since the element is destroy, then the VNode should be collected by GC as well
      // we do not want cause any mem leak because we have returned vm as a reference to users
      // so that we manually set it to false.
      render(null, container)
    },
  }
  const vnode = createVNode(
    MessageConstructor,
    props,
    isFunction(props.message) || isVNode(props.message)
      ? {
          default: isFunction(props.message)
            ? props.message
            : () => props.message,
        }
      : null
  )
  vnode.appContext = context || message._context

  render(vnode, container)
  // instances will remove this item when close function gets called. So we do not need to worry about it.
  appendTo.appendChild(container.firstElementChild!)

该代码创建了一个div,然后把MessageConstructor组件插入了这个div中,props是传递了参数

那么问题又来了,我不用的时候如何销毁它呢?

这个时候我们看到了props中有一个代码

...
onDestroy: () => {
   // since the element is destroy, then the VNode should be collected by GC as well
   // we do not want cause any mem leak because we have returned vm as a reference to users
   // so that we manually set it to false.
   render(null, container)
}
...

我觉得它就是销毁组件的了~(实际上肯定是得了)

这个时候就不多说了,大概的思路就是这样得了~~

如果要销毁组件,在子组件执行onDestroy或者父组件执行 render(null, container)即可

欢迎前端交流

QQ群:362909884
微信:sdsn10000