Vue.js中輕松解決v-for執(zhí)行出錯的三個方案
前言
Vue.js 是開源的一個前端開發(fā)庫,通過簡潔的 API 提供高效的數(shù)據(jù)綁定和靈活的組件系統(tǒng)。在前端紛繁復雜的生態(tài)中,Vue.js在近年來受到一定程度的關注,目前在 GitHub上已經有5000+。
本文是筆者在開發(fā)實踐中踩過的坑,總結和分享出來,希望對大家學習Vue有所幫助。下面來看看詳細的介紹:
【問題描述】
v-for遍歷數(shù)組中存在空值導致頁面報錯,情況如下:
開發(fā)框架是以Vue為模型綁定的核心,根據(jù)錯誤可以進行一個簡單的判斷:
▪ removeChild操作既然不是發(fā)生在開發(fā)者顯示書寫的代碼中,就應該是模型銷毀后Vue引擎移除dom節(jié)點導致的。
▪ 錯誤棧信息都在框架的代碼之內,此操作不可能是有用戶代碼觸發(fā)導致的。
開發(fā)者某一流程的操作,會100%穩(wěn)定地觸發(fā)出這一錯誤,此錯誤導致js執(zhí)行終端,整個程序陷入癱瘓無法工作,開發(fā)者的操作流程可以簡化為如下的步驟:
1. 訪問視圖A。
2. 訪問視圖B。
3. 回退歷史記錄到A。(錯誤發(fā)生在這里)
以上的跳轉關系都是視圖跳轉,也就是發(fā)生在路由系統(tǒng)之內的路由跳轉,按照路由邏輯,第三步的時候會依次執(zhí)行視圖的聲明周期函數(shù),包括:
▪ B視圖的unRender邏輯,包括beforeUnRender和afterUnRender。
▪ A視圖的Render,包括beforeRender和afterRender。
開發(fā)者只在beforeRender的階段進行了模型重置的操作,幾乎可以確定無疑,報錯就是由這幾行模型重置和賦值的操作引起的。層層排除可以尋找到使用簡單代碼重新此問題的方式。
【重現(xiàn)方式】
準備一個簡單的空工程,新建視圖test,一下的代碼分別為js/view/test.js和html/view/test.html,js/view/test.js中視圖對模型的操作可以完整反映重現(xiàn)此問題的流程。其中,setTimeout模擬的是ajax操作以讓數(shù)據(jù)在多個tick之后設置到模型以觀察Vue對dom節(jié)點的創(chuàng)建和銷毀。
$nextTick
之后,將test_arr置空的操作是為了使vue將此數(shù)據(jù)對應的dom節(jié)點銷毀,對應代碼如下:
以上的代碼可以穩(wěn)定重新問題,下面是解題思路。
【解決方案】
在不求甚解的狀態(tài)下,這個問題是比較容易解決的,這里有幾個臨時的解決方案。
▲方案一
從報錯信息Uncaught TypeError: Cannot read property 'removeChild' of null
可知,之所以發(fā)生這個問題是因為在null的對象上執(zhí)行了removeChild。
修改Vue框架代碼,將這里的代碼:
修改為:
▲方案二
深入地分析,為什么el.parentNode
會是null,通過上面重現(xiàn)的步驟發(fā)現(xiàn),當that.model.test_arr = ["","4","","5","6",""]
這段代碼設置發(fā)生后,v-for產生的dom節(jié)點之后3個,而不是5個,這種情況下el.parentNode
就是不存在的,所以產生了第二種解決方案,強制不給空數(shù)據(jù)的元素生成dom節(jié)點。
▲方案三
問題并不算是圓滿解決,正常的情況下框架應該具有魯棒性,適應不同的使用場景,不應該出現(xiàn)js報錯的問題,所以還有深入研究下去的必要。
在Vue中針對v-for指令有一個track-by的可選配置:
▪無track-by情況:數(shù)據(jù)修改時,無論值是否被修改,dom都被重新渲染。
▪有track-by情況:數(shù)據(jù)修改時,不變數(shù)據(jù)所在的dom不被重新渲染,已改變的數(shù)據(jù)所在dom才被重新渲染。
因為 v-for 默認通過數(shù)據(jù)對象的特征來決定對已有作用域和 DOM 元素的復用程度,這可能導致重新渲染整個列表。但是,如果每個對象都有一個唯一 ID 的屬性,便可以使用 track-by 特性給 Vue 一個提示,Vue因而能盡可能地復用已有實例。所以就有了第三種解決方案。
【原因分析】
v-for遍歷數(shù)組中存在空值導致頁面報錯,主要是遍歷條件里對值的判斷有問題。Vue為了保證對dom節(jié)點的復用,內置了一份按照id存取的dom緩存,通過對數(shù)據(jù)分析出dom_id,然后根據(jù)此id從緩存中獲取dom節(jié)點。由于不同的數(shù)據(jù)取到了相同的dom_id,所以沒有創(chuàng)建dom節(jié)點出來。但是,在最終數(shù)組置空,模型變更之后dom節(jié)點移除的時候卻為這些dom節(jié)點觸發(fā)了remove操作,也就是方案一中兼容的那些代碼:
所以問題必定出現(xiàn)在getTrackByKey這個函數(shù)的執(zhí)行上,以下是getTrackByKey的代碼:
Vue中對數(shù)據(jù)綁定的操作大大地提高了開發(fā)者應用開發(fā)的效率,但與此同時也伴隨著一些不易察覺的問題,尤其如本文中問題的重現(xiàn)條件比較復雜的情況下,測試不一定可以覆蓋到問題的觸發(fā)條件,這個時候就需要開發(fā)人員多一分警惕。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關文章
Vue中ElementUI分頁組件Pagination的使用方法
這篇文章主要為大家詳細介紹了Vue中ElementUI分頁組件Pagination的使用,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-05-05vue.config.js文件devServer字段的常用選項詳解
在?Vue?CLI?生成的?vue.config.js?文件中,devServer?字段用于配置開發(fā)服務器的選項,本文給大家介紹vue.config.js文件devServer字段的常用選項,感興趣的朋友一起看看吧2023-11-11vue2.0 根據(jù)狀態(tài)值進行樣式的改變展示方法
下面小編就為大家分享一篇vue2.0 根據(jù)狀態(tài)值進行樣式的改變展示方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03