更簡單的類名標簽
Semantic-UI使用了更簡單的類名聲明。用過Bootstrap的同學都會被其復雜的類名標簽折磨過,例如一個簡單的按鍵樣式,不論顏色或是大小,都需要btn-前綴聲明:
- <button?type="button"?class="btn?btn-primary?btn-lg?active">Primary?button</button>?
在Semantic-UI中,類名更接近自然表述:
- <button?class="ui?blue?large?active?button">Blue?Button</button>?
語義化的樣式聲明
樣式名并不是對某種組件進行的類型聲明,可以通用到其他組件中。例如對于Label(標簽)組件,也可用與button相同的CSS類聲明其樣式:
- <div?class="ui?blue?large?active?label">Blue?Label</div>?
這樣的好處是顯而易見的,CSS類名語義化,剛方便使用和學習。
類名構造模塊的實現
從以上細節可以看出,每個組件的類聲明均可由公用模塊生成,每個組件僅僅聲明本模塊可使用的Props即可。以Button舉例如下:
- import?PropHelper?from?'./PropHelper';?
- import?UiElement?from?'./UiElement';?
- ...?
- ?
- let?PROP_TYPES?=?['primary',?'size',?'color',?'basic',?'active',?...];?
- ?
- class?Button?extends?UiElement?{?
- ?????
- ????static?propTypes?=?{?
- ????????...PropHelper.createPropTypes(PROP_TYPES)?
- ????};?
- ?????
- ????render()?{?
- ?????????
- ????????let?style?=?this.createElementStyle(this.props,?PROP_TYPES,?'button');?
- ?????????
- ????????return?(?
- ????????????<div?id={this.props.id}?className={style}?tabIndex='0'>?
- ????????????????{this.props.children}?
- ????????????</div>?
- ????????);?
- ????}?
- ?????
- ????...?
- }??
Button類聲明了其可以使用的class類名,通過共通處理生成style即可。生成style的共同處理,由PropsHelper類負責完成。
PropsHelper
PropsHelper類主要的職責有兩個:
- 生成各組件所需的class類集合
- 生成各組件的props屬性檢查定義
PropsHelper作為工具類,相關處理過程中并無狀態參與,方法應該聲明為靜態方法(static)。
props屬性檢查
Semantci-UI中的所有class類屬性的集合是可枚舉的,這些屬性直接在PropsHelper中定義即可:
- const?BOOL_PROPS?=?['ui',?'active',?'disabled',?'circular',?...];?
- const?STRING_PROPS?=?['icon',?'appendClass',?...],?
- const?NUMBER_PROPS?=?['column',?'wide',?...],?
- const?COLLECTION_PROPS?=?['color',?'size',?'position',?...];??
對于每個組件的屬性檢查定義,可以遍歷傳入的屬性,并根據名字找到該屬性的PropTypes定義。
- class?PropsHelper?{?
- ?????
- ????...?
- ?????
- ????/**?
- ?????*?生成屬性檢查?
- ?????*/?
- ????static?createPropTypes(propTypes)?{?
- ?????????
- ????????let?result?=?{};?
- ????????propTypes.forEach(function(typeName,?index)?{?
- ?????
- ????????????if?(BOOL_PROPS.indexOf(typeName)?>=?0)?{?
- ??????????????result[typeName]?=?React.PropTypes.bool;?
- ????????????}?
- ????????????else?if?(STRING_PROPS.indexOf(typeName)?>=?0)?{?
- ??????????????result[typeName]?=?React.PropTypes.string;?
- ????????????}?
- ????????????else?if?(NUMBER_PROPS.indexOf(typeName)?>=?0)?{?
- ??????????????result[typeName]?=?React.PropTypes.number;?
- ????????????}?
- ????????????else?if?(COLLECTION_PROPS.indexOf(typeName)?>=?0)?{?
- ??????????????result[typeName]?=?React.PropTypes.oneOf(PROPS_VALUES[typeName]);?
- ????????????}?
- ????????});?
- ?????????
- ????????return?result;?
- ????}?
- }??
class類集合組裝
與createPropTypes同樣的思路,將傳入的組件props遍歷一遍,找到各自prop屬性的類型定義,根據類型定義編輯和組裝該組件的class類集合。
- class?PropsHelper?{?
- ?
- ????...?
- ?????
- ????/**?
- ?????*?根據屬性生成引用的class?
- ?????*/?
- ????static?createStyle(props,?types)?{?
- ?
- ????let?style?=?'';?
- ????for?(let?i?=?0;?i?<?types.length;?i++)?{?
- ??????let?type?=?types[i];?
- ??????if?(props.hasOwnProperty(type))?{?
- ????????style?+=?this.formatStyleValue(props[type],?type);?
- ??????}?
- ????}?
- ?
- ????return?style;?
- ??}?
- ???
- ??/**?
- ???*?格式化屬性對應的class?
- ???*/?
- ??static?formatStyleValue(value,?type)?{?
- ?
- ????//?如果是數字型屬性?
- ????if?(NUMBER_PROPS.indexOf(type)?>=?0)?{?
- ??????return?'?'?+?this.getNumberStr(value)?+?'?'?+?type;?
- ????}?
- ????else?if?(COLLECTION_PROPS.indexOf(type)?>=?0)?{?
- ??????if?(type?==?'size')?return?'?'?+?value;?
- ??????return?'?'?+?value?+?'?'?+?type;?
- ????}?
- ????else?if?(BOOL_PROPS.indexOf(type)?>=?0)?{?
- ?
- ??????if?(!value)?return?'';?
- ?
- ??????if?(type?==?'imaged')?return?'?image';?
- ??????if?(type?==?'iconed')?return?'?icon';?
- ??????if?(type?==?'long')?return?'?long?scrolling';?
- ??????if?(type?==?'equalWidth')?return?'';?
- ??????return?'?'?+?type;?
- ????}?
- ????else?if?(STRING_PROPS.indexOf(type)?>=?0)?{?
- ??????return?'?'?+?value;?
- ????}?
- ????else?{?
- ??????return?'';?
- ????}?
- ??}?
- }??
這樣實現以后,各組件在各自屬性的定義和class類聲明的處理時獲得了兩方面的益處:
- 屬性統一管理,不用再各自聲明
- 代碼復用性和耦合性更佳(特別是在復雜組件的使用中)