BUG重現
最近機票團隊在一個頁面布局復雜的地方發現一個BUG,非常奇怪並且不好定位,這類問題一般最后都會到我這里,這個問題是,改變dom結構,頁面卻不渲染!!!

如圖所示,我動態的改變了dom結構,結果頁面那一坨變得什么都沒有,相當奇怪!!!在PC模擬iPhone就可以重現,iPhone、note4等手機上也可重現,由於這種BUG我不是第一次碰到,很快便引起了注意,總結起來可以歸結於:
js代碼改變fixed元素的html結構(一般是動畫后並且布局相對復雜),頁面不會渲染
問題定位-分離法
本着發現問題,定位問題,解決問題的步驟,我開始了定位,這里的難點是,這類問題往往非常難以定位,因為他的dom tree相當復雜,首先我做了一個事情,直接將其htmlcss分離出來,擺脫js的原因,直接顯示該dom。

於是問題不在了,這個很令人費解,難道是js對其造成了影響?經過一輪糾纏,定位失敗開始二輪定位。
問題定位-最小化問題
這種問題確實不好處理的時候,光靠看頁面可能不能處理了,這個時候便把機票的代碼拿到本地,部署起來,做了幾件事情:
① 去掉該頁多余的業務代碼,基本上不完成任何功能
② 去掉多余的dom結構(由於我們是單頁應用,dom可能相對比較復雜)
打開對應業務代碼一看,洋洋灑灑3000行,立馬想吐:

這個時候一行行去讀代碼就是2B的行為了,直接找到那個顯示日歷的代碼:

然后稍作改動,把其它業務邏輯全部搞掉,事件綁定也搞掉,只留下顯示日歷的事件,直接一來點擊顯示日歷,這個時候形成的dom結構由4000多行變成了1000多行,但是依舊有BUG
問題定位-CSS重置
由於機票對日歷的樣式,做了重置,所以有理由懷疑是他們自己的css導致的問題,於是想去掉他們的css引用試了試,雖然樣式難看了點,但是問題依舊存在......

問題定位-js邏輯
這個時候便有理由懷疑其日歷顯示后,本身有一定邏輯功能導致出錯,於是看到了日歷show后面干的事情,並且為了防止dom結構過大,將月份顯示設置為1月。
都這個樣子了,他居然還是渲染不處理,有點傷害自尊!!!

因為這個日歷顯示時候有一個從右到左的動畫,這個時候將其動畫關掉,卻發現問題解決了!!!其中的代碼為zepto的實現,不是關鍵
$el.css({ '-webkit-transform': prepareCss, transform: prepareCss }) .show() .animate({ '-webkit-transform': 'translate(0, 0)', transform: 'translate(0, 0)' }, 500, 'ease-in-out', function() { $el.css({ '-webkit-transform': '', transform: '' }); });
問題定位成功-脫離文檔流的渲染
最后問題定位成功,至少從表現和處理來說是定位成功的,簡單來說:

動畫執行結束后,如果我改變的是fixed元素中的一個子單元的html,不會有反應,但是我們同時改變static元素便會引起一次渲染,尼瑪這是神馬鬼!!!
問題探索-渲染的差異
為了弄懂這個原因,我們得看到渲染的細節,這里做了一個對比:
不引起static dom變化

引起static dom變化





這里注意觀察最后一次paint便可以看見渲染出來的東西不一樣,導致這種的差異是什么呢,我們一次次的對比幾次不同


這里做一個差異對比,因為這里的static元素與fixed元素還有一些管理,我們這里操作與之完全無關的元素試試。事實證明沒有什么影響,所以這類問題的解決方案是:
移動端過多定位元素布局時,偶爾操作fixed元素html不會渲染,解決方案是同步改變與之相關的static元素,便會引導渲染
剛剛使用的是設置html,這里完全可以使用這種做法:
el.html(el.html())
可以達到相同的功能,但是問題導致原因依舊不可知......不可說不是一種遺憾!!!如果您知道這個問題的答案,請您留言。

