CSS 樣式規則的匹配算法實現
CSS 的完整英文名稱是: Cascading Style Sheets, 級聯樣式表. 除了可以定義豐富的樣式, 以及進行界面控件布局外, CSS 最重要的特性便是名字中的"級聯(Cascading)"一詞. 級聯代表了父子關聯, 天生便是和數據結構中的"樹"相關的.
我創建的CocoaUIiOS 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
原文鏈接: http://www.ideawu.net/blog/archives/897.html