因為當列表資料變化,vue 重新渲染列表時,會導致受影響的列表項的 DOM 從頁面移除,而 iframe 被移除後再新增回頁面一定會重新整理。
如果向列表的資料陣列的開頭或中間插入元素,又或者移除元素,vue 會將操作位置對應的 DOM 元素和之後的 DOM 元素統統移除,然後在新增回去。
沒看過 vue 原始碼,但是可以推斷,這一過程可能是,先移除所有受影響的元素,然後再將可用的元素新增到合適的位置;這一過程也有可能是使用 Element.replaceWith()
完成的,而該 API 也會將 DOM 元素從頁面中移除。從頁面移除 iframe,iframe 的 contentWindow 會銷燬載入的內容,重新新增到頁面,contentWindow 會重新載入 iframe 指定的 src,這一來一回,就導致了 iframe 狀態丟失。
基於 vue 這個更新列表 DOM 的原理,最好不在列表中使用 iframe。
如果列表資料不變,或者將列表資料當作一個棧來使用,那麼不會有 DOM 被移除後重新新增回頁面,這種情況下可以在列表中使用 iframe 。
如果列表資料多變,不僅僅是隻運算元據尾部,還會向列表其它位置進行插入或刪除操作,可以考慮透過視窗通訊的方式來實現狀態的儲存與恢復。
- 同域名的網頁,可以直接取得 iframe 的 contentWindow 物件,然後就可以讀取狀態了。contentWindow unload 的時候儲存狀態,再將狀態附加到 iframe 的 src 屬性上,iframe 重新新增回頁面時,內部頁面透過 location.href 來恢復狀態。
- 跨域的頁面,使用
window.postMessage
來通訊,contentWindow unload 的時候將其狀態傳送給呼叫它的頁面,然後呼叫它的頁面將狀態資料格式化後附加到 iframe 的 src 屬性上。資料恢復的過程和同源網頁沒差。
儲存與恢復 iframe 狀態的做法還是有些複雜的,如果在 vue 列表中使用 iframe 是必要的,就好好設計一下 iframe 狀態的儲存與恢復的功能。
如果是不必要的,果斷放棄。