Vue Portal实现

最近学习React的时候发现有个Vue没有的特性—Portal,利用 React.createPortal() 可以在任意的DOM节点上挂载组件,这个特性在做Modal组件时十分有用。

之前其实也用Vue实现过类似的效果

new Vue({
 el: this.el,
 render: (h: CreateElement) => {
   return h(VModal, { props, on: { input: (visible: boolean) => this.close() } });
 }
}); 

不过相比React还是不太直观,而且使用起来十分受限,基本上只有函数调用的组件能这样搞,对于挂载在模板中的组件还是不能如React一般任意挂载。

所以我上网搜了搜有没有相关实现,发现了一个portal-vue,这个库可以让组件在任意地方渲染,用法也很简单

<portal to="destination">
 <p>This slot content will be rendered wherever the <portal-target> with name 'destination'
   is  located.</portal-target></p>
</portal>

<portal-target name="destination">
 <!--
 This component can be located anwhere in your App.
 The slot content of the above portal component will be rendered here.
 -->
</portal-target> 

我顺便看了下其实现,大致可以用以下图解释:

portal-vue.png

Portal和PortalTarget在组件创建时会在wormhole中注册,Portal会在挂载成功时,调用sendUpdate方法,将Portal中的子组件(详细信息通过TransportInput)通过wormhole传送到PortalTarget,PortalTarget会计算出passengers,然后挂载在PortalTarget中

这种模式我们不能动态生成挂载节点,和React比还是有差距,所以这个库还提供 MountingPortal  组件将组件挂载在任意节点上。模式类似以下方法:

<mountingportal mountto="#external-target" to="external-target-name" append>
</mountingportal> 

emmm,只能说还是有差距