StyleSheet 的源碼位置在: LibrariesStyleSheetStyleSheet.jsjavascript
https://github.com/facebook/r...java
官方文檔react
StyleSheet 是用 RN 開發中提供樣式相關功能的工具集。android
它提供了下面幾個靜態方法和靜態屬性git
靜態方法: compose()
create()
flatten()
setStyleAttributePreprocessor()
github
靜態屬性: absoluteFill
absoluteFillObject
hairlineWidth
react-native
compose<T: DangerouslyImpreciseStyleProp>( style1: ?T, style2: ?T, ): ?T | $ReadOnlyArray<T> { // 判斷 style1 和 style2 是否都不是 null,若是都不是返回 [style1, style2] 這樣的數組 if (style1 != null && style2 != null) { return ([style1, style2]: $ReadOnlyArray<T>); } else { // 若是有一個是 null 則判斷下 style1 是否是 null,若是不是則返回 style1, 不然返回 style2, 因此實際這裏若是 style2 是 null 這個函數仍是有可能返回 null 的 return style1 != null ? style1 : style2; } },
用於建立 react native jsx 對象的 style 屬性數組
StyleSheetValidation 源碼位置: https://github.com/facebook/r...函數
// 假設咱們傳入 obj = { test: { color: "white" } } create<+S: ____Styles_Internal>(obj: S): $ObjMap<S, (Object) => any> { // 若是在開發環境下則驗證是否傳入了非法的屬性 if (__DEV__) { for (const key in obj) { // StyleSheetValidation.validateStyle 見下 // 這裏 key = "test", obj = { test: { color: "white" } } StyleSheetValidation.validateStyle(key, obj); if (obj[key]) { // Object.freeze 文檔: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze // 簡單來講就是不容許傳入的對象發生改變, 例如 a.a = 1 不會改變 a.a 的值 Object.freeze(obj[key]); } } } return obj; static validateStyle(name: string, styles: Object) { // 若是不是開發環境則不驗證 if (!__DEV__ || global.__RCTProfileIsProfiling) { return; } for (const prop in styles[name]) { // prop = "color" // styles = { test: { color: "white" } } // name = "test" // styles[name] = { color: "white" } // StyleSheetValidation.validateStyleProp 源碼見下 StyleSheetValidation.validateStyleProp( prop, styles[name], 'StyleSheet ' + name, ); } } static validateStyleProp(prop: string, style: Object, caller: string) { // 簡單來講就是 RN 內部維護一個叫作 allStylePropTypes 的 Map 對象,map 的 key 爲全部被容許的 style 名稱,例如 「color」 "fontSize",而 validateStyleProp 方法會去 allStylePropTypes 對象裏面查找傳入的 prop 是否存在,若是不存在則會報錯 if (!__DEV__ || global.__RCTProfileIsProfiling) { return; } // 若是 prop 不存在 allStylePropTypes 中,也就是傳入了錯誤的 prop, 例如傳入 prop = "test" if (allStylePropTypes[prop] === undefined) { const message1 = '"' + prop + '" is not a valid style property.'; const message2 = '\nValid style props: ' + JSON.stringify(Object.keys(allStylePropTypes).sort(), null, ' '); // 上面構建報錯信息,這裏拋出 error styleError(message1, style, caller, message2); } // allStylePropTypes[prop] 有多是一個函數,參考 StyleSheetValidation.js addValidStylePropTypes() 方法 // 這裏嘗試調用這個函數,若是這個函數返回了 error 則會將 error 拋出 const error = allStylePropTypes[prop]( style, prop, caller, 'prop', null, ReactPropTypesSecret, ); if (error) { styleError(error.message, style, caller); } }
flatten(打平) 的源碼在這個文件 https://github.com/facebook/r...工具
他的效果爲將 [{color:"white"}, {fontSize: 11}] 這種結構的對象變成深遞歸轉換成 {color: "white", fontSize: 11}, 注意這裏是深遞歸,也就是說 [ {corlor: "white", test: { fontSize: 10 }} ]
這種結構也能夠處理,不過 jsx 在 transform 的過程當中會驗證 style ,因此 test
會被報錯
function flattenStyle( style: ?DangerouslyImpreciseStyleProp, ): ?DangerouslyImpreciseStyle { // 處理邊界狀況 if (style === null || typeof style !== 'object') { return undefined; } // 若是不是數組天然沒法 flatten ,因此直接返回 if (!Array.isArray(style)) { return style; } const result = {}; for (let i = 0, styleLength = style.length; i < styleLength; ++i) { // 打平傳入的 style 對象,按照第一個例子這裏就可能爲 flattenStyle({color:"white"}), 最後獲得 {color:"white"} 這種結構 const computedStyle = flattenStyle(style[i]); if (computedStyle) { for (const key in computedStyle) { // 將值存在 result 中 result[key] = computedStyle[key]; } } } return result; }
setStyleAttributePreprocessor()
會改變 RN 內部用於處理 color(顏色)
,transform
,shadowOffset
的預處理器( preprocessor )
上面提到的幾個東西怎麼理解呢?
首先要明確一件事情,那就是開發者傳入的 style 的 color
transform
shadowOffset
屬性 RN 是不會直接使用的,而是先作處理,用於處理的函數就是預處理器
咱們來看看 color
的默認預處理器,這部分代碼過於底層,筆者的水平還不足以講解具體意思,大概意思是會將你傳入的 white, #FFFFFF hsla(0, 0%, 100%, 1)
等顏色格式轉換爲 32 位的整數。
function processColor(color?: ?(string | number)): ?number { if (color === undefined || color === null) { return color; } let int32Color = normalizeColor(color); if (int32Color === null || int32Color === undefined) { return undefined; } // Converts 0xrrggbbaa into 0xaarrggbb int32Color = ((int32Color << 24) | (int32Color >>> 8)) >>> 0; if (Platform.OS === 'android') { // Android use 32 bit *signed* integer to represent the color // We utilize the fact that bitwise operations in JS also operates on // signed 32 bit integers, so that we can use those to convert from // *unsigned* to *signed* 32bit int that way. int32Color = int32Color | 0x0; } return int32Color; }
這個就是預處理器的意思,transfrom
和 shadowOffset
也是同理。
等價於下方代碼
const absoluteFill = { position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, }
一個當前設備上能顯示的最細數值的常量。TODO PixelRatio 部分會在接下來的章節講解,以後會在連接放講解的超連接
源碼以下:
let hairlineWidth: number = PixelRatio.roundToNearestPixel(0.4); if (hairlineWidth === 0) { hairlineWidth = 1 / PixelRatio.get(); }