开始
需求很简单,因为一些原因我并不想在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