CSS 属性的分类
VideoNative 的 CSS 属性可以从以下几个来源获得:
VNML 的标签(Node)中写的内联样式
1
2
3<text style="color: red">
This is a text
</text>CSS 文件中的样式,即经过选择器匹配后的 CSS 属性
1
2
3
4
5
6
7.myTitle
{
height:auto;
width:auto;
font-size:26rpx;
color:#848494;
}- 继承属性
- 默认属性
- 复合属性
CSS 渲染流程
VideoNative 一套完整的脚本代码(VNML+CSS+JS+JSON),渲染出来的是一个 QVNPage
整个 CSS 的渲染流程如下:
- Page 打开的时候,将 CSS 文件中的属性读取并解析其值,存放到 QVNContext 的 QVNRichCss 中(注意此时只是属性集,至于会应用到哪些 Node 还不确定,需要根据选择器来匹配;同时为了效率,这个步骤只做一次)
- 读取 Node 中的内联样式(VNML 中写的),创建一个 ProperyMap
- Widget 节点
- 根据这个 ProperyMap解析 ID 和类名,将 PropertyMap 的值转为其属性集,以此得到内联属性
- 处理父亲的属性集,以此得到继承属性
- 根据 ID/类名/类型等选择器对 QVNContext 的 QVNRichCss 的样式进行匹配,以此得到从 CSS 文件中来的属性
- 在将属性应用到 View 节点之前,这里会执行一步整理复合属性
- 每个 Widget 都对应一个 AttributeSetter,AttributeSetter 会声明其感兴趣的属性。AttributeSetter 拿到属性集之后,会取出其感兴趣的属性,读取其值设置给 View
复合属性
首先陈述一个事实,在将 Widget 节点的属性集应用到 View 节点的时候,各个属性是一个接一个应用的(非同时),同时它们应用的顺序是不确定的
如果不同的属性之间有依赖,比如 View 节点拿到 A 属性的时候要根据 B 属性去设置 View,那么此时 B 属性如果还没设置过来,那么就会有问题
此时我们引入一个复合属性的概念,将有依赖的属性封装为一个复合属性,复合属性将做为一个整体设置给 View,以此解决应用顺序不确定的问题
复合属性的子属性的值是来自于原有的独立属性,原有的独立属性的值已经是经过继承、匹配选择器等操作得到的最终值
复合属性对开发者是透明的
别名属性
解析过程还涉及一个别名属性的概念,别名属性对开发者也是透明的
以 margin 为例,在 CSS 中,开发者可以写 margin:1px;
或 margin:1px 2px
或 margin:1px 2px 3px 4px
,也可以单独写 margin-top:1px
而 VideoNative 最终得到的属性集里面,并没有一个叫做 margin 的属性,而是 4 个单独的属性:marigin-top
, marigin-left
, marigin-bottom
, marigin-right
,margin 属性就是它们的别名属性
别名属性的解析
以 margin-top 属性的解析过程为例,标准的 CSS 属性解析过程是这样的,将传入的 value 通过 parseFunc 解析之后,放到属性集中。其中 parseFunc 负责将 string 转化为 QVNCSSValue,attrPairs 是 Widget 的属性集
1 | void QVNRichCssAttrType::parse(const std::string &value, IQVNRichCssAttrs &attrPairs) const |
而对 margin 的属性进行解析的时候,先调用别名 CSS 类型 QVNRichCssAliasAttrType 的 parse 方法(QVNRichCssAliasAttrType 是 QVNRichCssAttrType 的子类,所以该方法被重写)
1 | void QVNRichCssAliasAttrType::parse(const std::string &value, IQVNRichCssAttrs &attrPairs) const |
此时调用到了 VN_RICH_CSS_MARGIN_ALIAS_PARSER
1 | static QVNRichCssAliasAttrType::AliasParseFunc VN_RICH_CSS_MARGIN_ALIAS_PARSER = [](const std::string &token, IQVNRichCssAttrs &attrs, QVNRichCssAttrType::ParseFunc parseFunc) -> void |
别名解析函数将值通过 parseFunc 解析之后,设置给 margin-top
等属性