v-if與v-show造成部分元素丟失的問題——v-if複用元素問題

longxiaoming發表於2023-04-13

問題描述

在寫tab切換時遇到了一個問題,以下為簡化後的問題所在的程式碼:

<img v-if="tabIndex === 2" id="t1">
<div v-if="tabIndex === 2" id="t2"></div>
<div v-if="tabIndex === 2" id="t3"></div>
<div v-show="tabIndex === 2" id="t4">
    <div id="content"></div>
</div>

當頁面載入時,先向id為content的div中新增了一些元素:

function addContent() {
    const newDiv = document.createElement('div');
    newDiv.innerHTML = '123456789';
    document.getElementById('content').appendChild(newDiv);
}
  • 如果當tabIndex為2時執行addContent(),上述123456789能夠正常顯示;
  • 但如果:
    • 在此時將tabIndex改為1,再將tabIndex改為2,
    • 或者在tabIndex不為2時執行addContent(),再將tabIndex改為2,
      這兩種情況下,123456789都無法正常顯示。

問題探索

首先嚐試將目標元素輸出到控制檯。在切換tabIndex前,先獲取原來的元素:

var oldT4 = document.getElementById('t4');
var oldContent = document.getElementById('content');

此時輸出顯然能得到正確的結果。
然後在切換tabIndex後,再獲取新的元素:

var newT4 = document.getElementById('t4');
var newContent = document.getElementById('content');
console.log(oldT4, newT4);
console.log(oldContent, newContent);

此時會發現:

  • oldContent元素雖然能正常輸出,但在頁面上已經不存在了,此時oldContent僅僅是引用了一個不存在的元素;
  • newContent元素就是當前頁面上的content元素,但其中的內容已被清空。
  • newT4元素就是當前頁面上的t4元素。
  • oldT4卻離奇的變為了t2元素,console.log(oldT4 === document.getElementById('t2'))的結果為true

問題原因

這是因為t4tabIndex切換時,複用了被v-if隱藏的t2元素,複用時會重新渲染t4內的所有內容,這種情況下,動態新增到content元素中的內容就會被清空。
這裡複用的順序則是從第一個同樣為div的被v-if隱藏的元素開始複用,即t2元素。類似的,如果此時進一步將t2元素的v-if修改成v-show,則oldT4就會去複用t3元素。

解決方案

要保留content元素中的內容,可以考慮:

  1. t2t3v-if改成v-show
  2. 如果確實不方便修改v-if,則可以給t2t3新增key屬性,使其不會被複用。

相關文章