Multilayer teleport can not be remove completely
Version
3.0.11
Reproduction link
https://codepen.io/jsqy/pen/xxgJWdw
Steps to reproduce
This is just one example, the reality will be more complex, but the principle should be the same.
Reproduction link: Click the "change" button to control the alternate display of the two divs, but the teleport in the #pop does not uninstall with the uninstall of the div.
What is expected?
Because I often use teleport in components, and the component's slot may also contain teleport, the elements in the #pop are not completely unmounted.
What is actually happening?
A multi-layered teleport can cause exceptions.
This seems to be more an issue caused by the element re-use between v-if and v-else. Adding a key
can be used as a workaround:
<div id="app">
<div v-if="mode">
Mode 1
<teleport to="#pop" :disabled="dis">
<div class="port" :key="1">
Port 1
<teleport to="#pop" :disabled="dis">
<div class="port" style="left: 200px;" :key="1">
Port 2
</div>
</teleport>
</div>
</teleport>
</div>
<div v-else>
Mode 2
<teleport to="#pop" :disabled="dis">
<div class="port" :key="2">
Port 3
<teleport to="#pop" :disabled="dis">
<div class="port" style="left: 200px;" :key="2">
Port 4
</div>
</teleport>
</div>
</teleport>
</div>
<div>
<input type="button" @click="mode = !mode" value="Change mode" /> <input type="button" @click="dis = !dis" value="Change disabled" />
</div>
<div>Click "Change mode" button multiple times, u can see a lot of "port2" and "port4", which is obviously not right.</div>
</div>
<div id="pop"></div>
I don't think this has anything to do with element re-use, but rather the nested teleport not being unmounted correctly.
When the el of Port1 was removed, Port2 was not removed correctly because it was mounted under pop.
My idea was to set optimized to false on unmount if it contained a nested teleport. this may not be a good solution, so I didn't submit a PR.
Finally, I submitted a PR and didn't think of a better way.
This seems to be more an issue caused by the element re-use between v-if and v-else. Adding a
key
can be used as a workaround:<div id="app"> <div v-if="mode"> Mode 1 <teleport to="#pop" :disabled="dis"> <div class="port" :key="1"> Port 1 <teleport to="#pop" :disabled="dis"> <div class="port" style="left: 200px;" :key="1"> Port 2 </div> </teleport> </div> </teleport> </div> <div v-else> Mode 2 <teleport to="#pop" :disabled="dis"> <div class="port" :key="2"> Port 3 <teleport to="#pop" :disabled="dis"> <div class="port" style="left: 200px;" :key="2"> Port 4 </div> </teleport> </div> </teleport> </div> <div> <input type="button" @click="mode = !mode" value="Change mode" /> <input type="button" @click="dis = !dis" value="Change disabled" /> </div> <div>Click "Change mode" button multiple times, u can see a lot of "port2" and "port4", which is obviously not right.</div> </div> <div id="pop"></div>
I also don't think it has an issue with element re-use, I've written a new demo that doesn't involve v-if and v-else, and after clicking "Unmounted", only the first layer of teleport is destroyed.
The new link is: https://codepen.io/jsqy/pen/MWJqWLN
Examples written using v-if in the topic post are simply simplified problem reproduction, which is more complicated when combined with components, and the use of ":key"'s "workaround" does not solve the problem.