vue3 Teleport 传送门
先放个官方文档链接~
某位同事研究vue3时,发现vue3的Teleport使用起来有点问题。
<template> <div class="test">1 <div class="qwe">2</div> <teleport to=".qwe">333</teleport> //情况一:失败并报错 </div> <teleport to=".qwe">333</teleport> //情况二:成功传送 </template>
去官方文档看了一下,有如下提示
也就是说,元素最好要挂载到#app的外面,原理其实是解析到teleport的时候,需要能获取到to指向的dom元素。
自己试了一下,发现确实如此,听官方的话,不行就加个v-if吗,等mounted之后再获取,so easy~(链接)
但是为了了解原理,我还是启了个vue3项目,结果发现在不考虑v-if的情况下,情况一和情况二都失败了。
自己测试了一下,也打断点看了看源码(代码里直接搜resolveTarget方法),最终得出了结论。
网页版和项目版的区别,就在于teleport标签的位置是不是vue根标签#app的子标签,项目版的文件嵌套了路由,所以就有好几层。
源码原理:vue由虚拟dom解析到真实dom,确实是由上而下进行的。但是根标签#app是一直存在的(真要删也不是不行),所以尤雨西才推荐我们把to指向#app外面的标签,比如它爸爸body标签,这样可以保证无论vue应用怎么变化,teleport的to都能获取到对应的标签,然后传送过去。
以下两个例子就能解释明白了:
// 一、 App.vue 在根应用下
// 这时,Vue是从上到下解析并渲染的,先#test,再Teleport标签,再.test1。所以执行到Teleport标签时,就能获取到.text标签了。 <template> <div id="test"> <p>我是test</p > <div class="text"> <div class="teleport"> <p>我是teleport</p > </div> </div> <Teleport to=".text"> <h3>嗨,我是teleport的兄弟</h3> </Teleport> <div class="test1">7777</div> </div> </template>
// 二、 App.vue ,但不在根应用下
// 这时,vue解析是先看#app底下的#aaa,发现只有一个标签,就进入并解析其所有子标签,待所有子标签解析完成,才会对整个#aaa进行渲染。
// 所以,是先解析#test、.text、<Teleport>,但是并没有进行渲染,这时候在resolveTarget打断点,会发现element里只有一个孤零零的#app,里面啥都没
// 所以解析到Teleport的时候,获取不到to属性对应的标签,就报错并且失败了 <template> <div id="#aaa"> <div id="test"> <p>我是test</p > <div class="text"> <div class="teleport"> <p>我是teleport</p > </div> </div> <Teleport to=".text"> <h3>嗨,我是teleport的兄弟</h3> </Teleport> <div>7777</div> </div> </div> </template>