如果你习惯在Vue里使用css简写属性,记得避开这个坑

栏目: CSS · 发布时间: 7年前

内容简介:首先我们来这么一个问题, 这里是完整的jsfiddle demo orcodepen demo给一个元素绑定两个边框样式, 右侧和底部都为1px的红色边框然后用一个按钮(或者任何方式)将样式换成下面的样式, 一个1px的绿色边框,和1px的红色右侧边框。

首先我们来这么一个问题, 这里是完整的jsfiddle demo orcodepen demo

给一个元素绑定两个边框样式, 右侧和底部都为1px的红色边框

styleA: {
            borderBottom: '1px solid red',
            borderRight: '1px solid red'
	};
复制代码

然后用一个按钮(或者任何方式)将样式换成下面的样式, 一个1px的绿色边框,和1px的红色右侧边框。

styleB: {
            border: '1px solid green',
            borderRight: '1px solid red'
	};
复制代码

我们期望的结果应该是右侧边框是红色的,其余三边的边框是绿色的,但实际结果却是所有边都是绿色的, 这里已经出现了问题, 然后再点击按钮,将样式切换回去, 此时期望的结果应该是跟一开始一样: 右侧和底部都为1px的红色边框, 但实际结果却是只剩下底部的边框是红色的,右侧的边框就像消失了一样。

那么, 右侧的边框样式是不是真的消失了呢? 是不是从第一次切换就消失了呢?(这好像也能符合第一次全都是绿色边框的表现),是 CSS 的bug吗?

这个 style 的替换过程是在 Vue 里帮我们实现的,是跟虚拟节点 vNode 的渲染有关,接下来让我们去 Vue 的源码看一下这个问题到底是怎么样造成的。

Vue更新视图机制

首先,vue视图的更新通过 updateComponent 进行, updateComponent 会执行一个 update 的方法进行更新视图,update会从根节点进行 patch 操作, patch 操作会依次遍历虚拟节点树的所有vnode节点,深度优先的遍历方式。

通常 patch 操作会update以下几个部分

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)
复制代码

这里我们只需要关注第5个方法: updateStyle , 那么这个方法里做了什么呢? 看一下核心逻辑:

如果你习惯在Vue里使用css简写属性,记得避开这个坑

可以看到这段代码的主要逻辑是用新的样式覆盖旧的样式,这里的setProp是对 element.style 进行修改,也就是原生 CSSStyleDeclaration 对象的实例。

''

看起来没什么问题,一切都很符合逻辑,那么是什么造成了上面的现象呢?

一切的罪魁祸首都在这个 border 样式的简写属性(shorthand property)上。

简写属性有什么特殊的地方呢? 最直接的就是当对一个简写属性赋值,例如:

border: 1px solid green;
复制代码

这个赋值会被转换为:

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"
复制代码

也就是说 borderTop , borderLeft , borderRight , borderBottom 也都被赋值了.

原因分析

所以,回到上面的那个切换过程,根据 updateStyle 源码进行分析:

  • styleA 切换为 styleB 时,

    1. 第一个 for 循环, borderBottom 不在 oldStyle 中,被清空, borderRight 在 oldStyle 中,保留了下来。

    2. 第二个 for 循环, border 不在 oldStyle 中,设置 border 的值,注意此时 borderTop , borderLeft , borderRight , borderBottom 也都被赋值了,然后 borderRight 与 oldStyle 中保留下来的值相等, 跳过这次赋值。

    3. 最后的结果就是 borderTop , borderLeft , borderRight , borderBottom 都显示 border 的值。

  • styleB 切换回为 styleA 时,

    1. 第一个 for 循环, border 不在 oldStyle 中, border 的值被清空,此时 borderTop , borderLeft , borderRight , borderBottom 也都被清空,然后 borderRight 在 oldStyle 中, 跳过这次赋值。

    2. 第二个 for 循环, borderBottom 不在 oldStyle 中, borderBottom 被赋值, borderRight 与 oldStyle 中保留下来的值相等, 跳过这次赋值

    3. 最后的结果也就是只剩下了 borderBottom 的值。

解决方案

那么,原理搞清楚了,有什么好的解决方案呢? 这个问题在Vue的github上已经被提过 issue 了,看下尤雨溪的官方回复

This is a wontfix. It's impractical to handle all the possible shorthand variations in the diffing algorithm. The solution is: do not use shorthand properties in inline styles.
If you really have to, e.g. you are allowing the user to edit the css arbitrarily, then the workaround is giving the element in question a key that equivalents to the hash of its inline styles. This forces the element to be replaced fresh when its inline styles change.

这个问题被定性为了一个 wontfix ,但也给出了有效的 解决方案 :

  • 给这个元素一个用样式生成的hash值作为 key , 当样式有任何变化的时候, key 就会变化,在 Vue 的更新渲染逻辑中,如果元素的 key 发生变化,那么 oldstyle 就是空对象,就不会出现上面的问题了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法分析导论(第2版)(英文版)

算法分析导论(第2版)(英文版)

[美]Robert Sedgewick(罗伯特•塞奇威克)、[美]Philippe Flajolet(菲利普•弗拉若莱) / 电子工业出版社 / 2015-6 / 128.00元

《算法分析导论(第2版)(英文版)》全面介绍了算法的数学分析中所涉及的主要技术。涵盖的内容来自经典的数学课题(包括离散数学、初等实分析、组合数学),以及经典的计算机科学课题(包括算法和数据结构)。《算法分析导论(第2版)(英文版)》的重点是“平均情况”或“概率性”分析,书中也论述了“最差情况”或“复杂性”分析所需的基本数学工具。 《算法分析导论(第2版)(英文版)》第 1 版为行业内的经典著......一起来看看 《算法分析导论(第2版)(英文版)》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

SHA 加密
SHA 加密

SHA 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具