摘要:首先將不存在于中的的樣式設(shè)置為然后再設(shè)置與中樣式值不相等的的樣式看起來(lái)沒(méi)什么問(wèn)題,一切都很符合邏輯,那么是什么造成了上面的現(xiàn)象呢一切的罪魁禍?zhǔn)锥荚谶@個(gè)樣式的簡(jiǎn)寫(xiě)屬性上。
引出問(wèn)題
首先我們來(lái)這么一個(gè)問(wèn)題, 這里是完整的 jsfiddle demo or codepen demo
給一個(gè)元素綁定兩個(gè)邊框樣式, 右側(cè)和底部都為1px的紅色邊框
styleA: { borderBottom: "1px solid red", borderRight: "1px solid red" };
然后用一個(gè)按鈕(或者任何方式)將樣式換成下面的樣式, 一個(gè)1px的綠色邊框,和1px的紅色右側(cè)邊框。
styleB: { border: "1px solid green", borderRight: "1px solid red" };
我們期望的結(jié)果應(yīng)該是右側(cè)邊框是紅色的,其余三邊的邊框是綠色的,但實(shí)際結(jié)果卻是所有邊都是綠色的, 這里已經(jīng)出現(xiàn)了問(wèn)題, 然后再點(diǎn)擊按鈕,將樣式切換回去, 此時(shí)期望的結(jié)果應(yīng)該是跟一開(kāi)始一樣: 右側(cè)和底部都為1px的紅色邊框, 但實(shí)際結(jié)果卻是只剩下底部的邊框是紅色的,右側(cè)的邊框就像消失了一樣。
那么, 右側(cè)的邊框樣式是不是真的消失了呢? 是不是從第一次切換就消失了呢?(這好像也能符合第一次全都是綠色邊框的表現(xiàn)),是CSS的bug嗎?
這個(gè)style的替換過(guò)程是在Vue里幫我們實(shí)現(xiàn)的,是跟虛擬節(jié)點(diǎn)vNode的渲染有關(guān),接下來(lái)讓我們?nèi)?b>Vue的源碼看一下這個(gè)問(wèn)題到底是怎么樣造成的。
Vue更新視圖機(jī)制首先,vue視圖的更新通過(guò)updateComponent進(jìn)行, updateComponent會(huì)執(zhí)行一個(gè)update的方法進(jìn)行更新視圖,update會(huì)從根節(jié)點(diǎn)進(jìn)行patch操作, patch操作會(huì)依次遍歷虛擬節(jié)點(diǎn)樹(shù)的所有vnode節(jié)點(diǎn),深度優(yōu)先的遍歷方式。
通常patch操作會(huì)update以下幾個(gè)部分
0: ? updateAttrs(oldVnode, vnode) 1: ? updateClass(oldVnode, vnode) 2: ? updateDOMListeners(oldVnode, vnode) 3: ? updateDOMProps(oldVnode, vnode) 4: ? updateStyle(oldVnode, vnode) 5: ? update(oldVnode, vnode) 6: ? updateDirectives(oldVnode, vnode)
這里我們只需要關(guān)注第5個(gè)方法:updateStyle, 那么這個(gè)方法里做了什么呢?
看一下核心邏輯:
可以看到這段代碼的主要邏輯是用新的樣式覆蓋舊的樣式,這里的setProp是對(duì)element.style進(jìn)行修改,也就是原生CSSStyleDeclaration對(duì)象的實(shí)例。
首先將不存在于newStyle中的oldStyle的樣式設(shè)置為"",
然后再設(shè)置與oldStyle中樣式值不相等的newStyle的樣式,
看起來(lái)沒(méi)什么問(wèn)題,一切都很符合邏輯,那么是什么造成了上面的現(xiàn)象呢?
一切的罪魁禍?zhǔn)锥荚谶@個(gè)border樣式的簡(jiǎn)寫(xiě)屬性(shorthand property)上。
簡(jiǎn)寫(xiě)屬性有什么特殊的地方呢?
最直接的就是當(dāng)對(duì)一個(gè)簡(jiǎn)寫(xiě)屬性賦值,例如:
border: 1px solid green;
這個(gè)賦值會(huì)被轉(zhuǎn)換為:
borderWidth: "1px" borderStyle: "solid" borderColor: "green" borderTop: "1px solid green" borderTopColor: "green" borderTopStyle: "solid" borderTopWidth: "1px" borderRight: "1px solid green" borderRightColor: "green" borderRightStyle: "solid" borderRightWidth: "1px" borderLeft: "1px solid green" borderLeftColor: "green" borderLeftStyle: "solid" borderLeftWidth: "1px" borderBottom: "1px solid green" borderBottomColor: "green" borderBottomStyle: "solid" borderBottomWidth: "1px"
也就是說(shuō)borderTop, borderLeft, borderRight, borderBottom也都被賦值了.
原因分析所以,回到上面的那個(gè)切換過(guò)程,根據(jù)updateStyle源碼進(jìn)行分析:
從styleA切換為styleB時(shí),
第一個(gè)for循環(huán), borderBottom不在 oldStyle 中,被清空,borderRight在 oldStyle 中,保留了下來(lái)。
第二個(gè)for循環(huán), border不在 oldStyle 中,設(shè)置border的值,注意此時(shí)borderTop, borderLeft, borderRight, borderBottom也都被賦值了,然后borderRight與 oldStyle 中保留下來(lái)的值相等, 跳過(guò)這次賦值。
最后的結(jié)果就是 borderTop, borderLeft, borderRight, borderBottom都顯示 border的值。
從styleB切換回為styleA時(shí),
第一個(gè)for循環(huán), border不在 oldStyle 中,border的值被清空,此時(shí)borderTop, borderLeft, borderRight, borderBottom也都被清空,然后borderRight在 oldStyle 中, 跳過(guò)這次賦值。
第二個(gè)for循環(huán), borderBottom不在 oldStyle 中,borderBottom被賦值,borderRight與 oldStyle 中保留下來(lái)的值相等, 跳過(guò)這次賦值
最后的結(jié)果也就是只剩下了borderBottom的值。
解決方案那么,原理搞清楚了,有什么好的解決方案呢? 這個(gè)問(wèn)題在Vue的github上已經(jīng)被提過(guò)issue了,看下尤雨溪的官方回復(fù)
這個(gè)問(wèn)題被定性為了一個(gè)wontfix,但也給出了有效的解決方案:
給這個(gè)元素一個(gè)用樣式生成的hash值作為key, 當(dāng)樣式有任何變化的時(shí)候,key就會(huì)變化,在Vue的更新渲染邏輯中,如果元素的key發(fā)生變化,那么oldstyle就是空對(duì)象,就不會(huì)出現(xiàn)上面的問(wèn)題了。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/98957.html
摘要:首先將不存在于中的的樣式設(shè)置為然后再設(shè)置與中樣式值不相等的的樣式看起來(lái)沒(méi)什么問(wèn)題,一切都很符合邏輯,那么是什么造成了上面的現(xiàn)象呢一切的罪魁禍?zhǔn)锥荚谶@個(gè)樣式的簡(jiǎn)寫(xiě)屬性上。 引出問(wèn)題 首先我們來(lái)這么一個(gè)問(wèn)題, 這里是完整的 jsfiddle demo or codepen demo 給一個(gè)元素綁定兩個(gè)邊框樣式, 右側(cè)和底部都為1px的紅色邊框 styleA: { ...
摘要:學(xué)習(xí)內(nèi)容,基本語(yǔ)法和概念,打包工具,實(shí)戰(zhàn)操作參考文獻(xiàn)官網(wǎng)官方資料庫(kù)全家桶全家桶文檔概念前端框架借助可以實(shí)現(xiàn)手機(jī)開(kāi)發(fā)前端框架是一套構(gòu)造用戶(hù)界面的框架,只關(guān)于視圖層前端的主要工作室跟用戶(hù)界面打交道,中的,實(shí)現(xiàn)界面效果框架是為了提高開(kāi)發(fā) 學(xué)習(xí)內(nèi)容 1,Vue基本語(yǔ)法和概念 2, 打包工具 Webpack , Gulp3,實(shí)戰(zhàn)操作 參考文獻(xiàn):官網(wǎng): https://cn.vuejs.org...
摘要:學(xué)習(xí)內(nèi)容,基本語(yǔ)法和概念,打包工具,實(shí)戰(zhàn)操作參考文獻(xiàn)官網(wǎng)官方資料庫(kù)全家桶全家桶文檔概念前端框架借助可以實(shí)現(xiàn)手機(jī)開(kāi)發(fā)前端框架是一套構(gòu)造用戶(hù)界面的框架,只關(guān)于視圖層前端的主要工作室跟用戶(hù)界面打交道,中的,實(shí)現(xiàn)界面效果框架是為了提高開(kāi)發(fā) 學(xué)習(xí)內(nèi)容 1,Vue基本語(yǔ)法和概念 2, 打包工具 Webpack , Gulp3,實(shí)戰(zhàn)操作 參考文獻(xiàn):官網(wǎng): https://cn.vuejs.org...
閱讀 1662·2021-09-26 09:55
閱讀 5278·2021-09-22 15:40
閱讀 2022·2019-08-30 15:53
閱讀 1505·2019-08-30 11:15
閱讀 1723·2019-08-29 15:41
閱讀 1878·2019-08-28 18:13
閱讀 3154·2019-08-26 12:00
閱讀 1678·2019-08-26 10:30