設定面板輸入了一段文字,收合再打開卻變空白。先看收合條件用了 v-if還是 v-show,再確認文字狀態放在哪個元件。v-if不顯示時會拆掉對應內容;如果輸入草稿只存在子元件本地,重新建立子元件就會重新初始化。
v-show主要切換CSS display,內容仍留在DOM裡。這讓同一個子元件可以保留本地輸入,但也代表它只是不可見,並沒有卸載。選哪一種,不是看名字哪個較好,而是看你希望收合時保留還是重建這份狀態。
先把草稿放在子元件本地
以下DraftField每次建立時,把文字初始化為空。沒有把v-model綁到父頁來源,因此能看清子元件生命週期對本地草稿的影響。
<!-- DraftField.vue -->
<script setup>
import { ref } from 'vue'
const draft = ref('')
</script>
<template>
<input v-model="draft" aria-label="測試草稿">
</template>
如果你的表單草稿其實在父元件,子元件拆掉後父ref仍存在,就可能重新把原文字傳回來。這時文字保持,不代表v-if沒有卸載子元件。要比較元件本地狀態,就像此例一樣讓兩份草稿各自存在自己的子元件裡。
測試時不要把兩個輸入都綁同一個父頁變數。那樣其中一個改值,另一個也顯示相同文字,收合後重建又拿到父值;你會測到父來源共享,而不是v-if與v-show的差別。
同一個子元件,兩個獨立開關
父頁分別控制兩份DraftField。一個用v-if,一個用v-show,初始都顯示。按鈕只是切換開關,不清除或保存文字。
<script setup>
import { ref } from 'vue'
import DraftField from './DraftField.vue'
const ifOpen = ref(true)
const showOpen = ref(true)
</script>
<template>
<button @click="ifOpen = !ifOpen">切換if</button>
<DraftField v-if="ifOpen" />
<button @click="showOpen = !showOpen">切換show</button>
<DraftField v-show="showOpen" />
</template>
兩個開關是不同狀態,所以操作其中一個不應順便改另一個。先在各輸入打Keep,分別收合,再重新開啟。若程式另有重設功能,先不要接進此案例,避免把主動清空與生命週期造成的初始化混在一起。
看DOM、文字與掛載次數
本文使用Vue3.5.43與真Chromium操作。收合後,v-if對應輸入的DOM數量是0;v-show對應輸入仍有1個,但不可見。重新開啟後,if那份文字變成空字串,show那份仍是Keep。
案例也記錄子元件的mounted次數:if為2,show為1。這與DOM和文字一起說明前者建立了新的子元件,後者保留原元件。不是只從「看不到」推測發生哪種操作,而是直接核對元素存在與生命週期。
讀者可以在DraftField的onMounted加一個測試計數,或觀察瀏覽器DOM。這些只是本地合成草稿的比較,不代表真表單資料已保存。收合後文字仍在畫面來源裡,也不能當成伺服器已經收到它。
如果測到兩者都保持文字,先查草稿是否其實在父層、是否有從props重新載入、是否用了其他快取機制。若兩者都變空,則查按鈕或watcher是否主動清空。保留最小例子,才能把額外邏輯的影響分開。
v-show保留狀態,也保留元件的存在
面板不顯示時,v-show不等於元件停止所有工作。元件仍掛載,計時器、watcher或外部訂閱是否繼續運作,取決於你的實作。需要收合時暫停工作,就按開關條件管理,不要只靠display none。
例如一個定時重新查資料的面板,文字需要保留,但收合時不想發請求,可以保留元件,同時讓請求流程讀取面板是否開啟。這是工作是否繼續的需求,與DOM是否拆掉不同。本文沒有測網路或計時器,只提醒不要把兩者當成同一個開關。
相對地,v-if切走會卸載對應子元件,但元件內若建立了需要自行清理的外部資源,也應在適當卸載流程處理。不能把「用了v-if」當成每個自己建立的計時器都自動清掉的保證。
先決定取消與重開的產品行為
如果收合是暫時把面板藏起來,重新打開通常可能希望保留未提交文字,v-show或更高層草稿狀態都是可考慮的方法。如果收合等於取消編輯,重新建立乾淨草稿可能正是預期;此時不要為了讓文字留住就改成v-show,反而違反取消行為。
如果草稿需要跨不同頁面或元件重建仍保留,可以把來源放到適合的父層或狀態管理,並明確處理保存與清除。這是資料擁有者的設計,不是單靠一個渲染指令就能涵蓋所有需求。
未提交草稿與已保存值也要分清。保留本地草稿可以減少輸入重做,卻不能取代保存結果。頁面重載、導覽離開或資源切換時要怎麼處理,仍應由真正的表單流程決定。
初始成本與切換頻率也不同
Vue官方條件渲染指南說明,v-if具有惰性,初始條件不成立時不建立內容;v-show則先渲染,再按條件隱藏。因此一個幾乎不打開、內容又複雜的區塊,與高頻開關的簡單面板,不一定適合相同選擇。
這不表示可以為所有網站指定固定的效能門檻。依元件內容、初始化工作和使用情境量測,才知道差異。本文的輸入案例很小,重點是狀態與生命週期,不拿它的操作結果推成全站效能建議。
v-show需要能控制實際元素的display;不同根節點結構與元件包裝也應核對。不要直接對某個複雜元件加指令後,假定每個內部區塊都會按預期隱藏。先檢查實際DOM與可見性,再確認收合範圍。
KeepAlive是另一個需求
若要快取動態元件切換的實例,Vue另有KeepAlive。它有自己的啟用、停用與生命週期,不應被拿來當所有v-if草稿問題的通用補丁。先判斷你是在同一面板切換可見性,還是在切換元件實例,再看是否需要快取。
本例不使用KeepAlive,也不把其行為冒作已經測過。對一般收合輸入,先弄清草稿在哪裡與收合應否重設,通常就能選對方法。只有確實需要跨元件切換保留實例時,再增加相應機制與測試。
修正後至少核輸入、收合、重開與真正取消四個步驟。文字保持或變空都可以是正確結果,只要符合明確需求。最重要的是不要把父層保存的值,誤認為子元件從未被拆掉。
如果採v-show保留面板,但取消必須清空草稿,應明確執行重設,例如讓擁有draft的元件把值回到初始化狀態,再收合。不要期待切換display能同時代做清除。分開設計暫時收合與取消修改按鈕,也能讓使用者知道重新打開後會看到保留文字還是乾淨表單。

評論0