转载

CSS 样式规则的匹配算法实现

CSS 的完整英文名称是: Cascading Style Sheets, 级联样式表. 除了可以定义丰富的样式, 以及进行界面控件布局外, CSS 最重要的特性便是名字中的"级联(Cascading)"一词. 级联代表了父子关联, 天生便是和数据结构中的"树"相关的.

我创建的 CocoaUI iOS UI 框架, 是一个使用 CSS 进行 iOS 上流式布局的开发框架, 极大地方便了 iOS 应用的界面开发, 轻松适配多种屏幕. 因为 CocoaUI 使用 CSS 来进行界面布局和定义界面样式, 所以需要对 CSS 的样式规则进行匹配, 将某一条 CSS 样式作用到某一个 UIView(IView) 上面.

例如, 下面这条常见的 CSS 样式定义:

.a .b{     background: #f00; }

这条样式定义表示, 对于具有名为"a"的 class 属性某个节点(界面控件), 他的所有带有"b" class 属性的子控件, 背景都设置为红色(#f00).

在代码中, 要怎么实现这样的逻辑呢? 因为, 程序 = 数据结构 + 算法, 所以, 数据结构是这样定义的:

class Style {     array elements[];     string css;     bool match(Dom node); }

Elements 就是以 .a, .b 作为元素的数组.

接下来, 要实现 match() 方法, 该方法传入一个控件, 然后判断这个控件是否被这条样式规则命中.

我们讨论样式规则时, 是从左到右(Left To Right), 但代码中实现时, 其实是从右到左(Right To Left), 也就是说, elements 要倒序来判断.

首先, 我样要判断最后一个 element(也就是关键 element) 是否匹配传入的 node. 如果不匹配, 那就是不匹配了, 不需要再做额外的判断. 这也是为什么称之为"关键"的原因.

接着, 再判断 node 的父节点 parent 和倒数第 2 个 element. 如果匹配呢, 接着判断父节点的父节点(parent.parent) 和倒数第 3 个 element. 如果不匹配呢? 倒数第二个节点不动, 让倒数第二个节点和 parent.parent 匹配.

如果 Dom 节点已经到顶了, 而 element 还没匹配到第 1 个, 那么, match() 返回 false. 另一种情况, 如果 element 先匹配完, 那么 match() 返回 true.

相关代码可以看这里: https://github.com/ideawu/cocoaui/blob/master/IKit/IKit/css/IStyleRule.m#L65

正文到此结束
Loading...