1- import { isObject , isArray , dash2hump , cached , isEmptyObject , hasOwn } from '@mpxjs/utils'
2- import { Dimensions , StyleSheet } from 'react-native'
1+ import { isObject , isArray , dash2hump , cached , isEmptyObject , hasOwn , getFocusedNavigation , noop } from '@mpxjs/utils'
2+ import { StyleSheet , Dimensions } from 'react-native'
3+ import { reactive } from '../../observer/reactive'
34import Mpx from '../../index'
45
5- const rawDimensions = {
6- screen : Dimensions . get ( 'screen ' ) ,
7- window : Dimensions . get ( 'window ' )
6+ global . __mpxAppDimensionsInfo = {
7+ window : Dimensions . get ( 'window ' ) ,
8+ screen : Dimensions . get ( 'screen ' )
89}
9- let width , height
10+ global . __mpxSizeCount = 0
11+ global . __mpxPageSizeCountMap = reactive ( { } )
1012
11- function customDimensions ( dimensions ) {
13+ global . __classCaches = [ ]
14+ global . __GCC = function ( className , classMap , classMapValueCache ) {
15+ if ( ! classMapValueCache . get ( className ) ) {
16+ const styleObj = classMap [ className ] ?. ( )
17+ styleObj && classMapValueCache . set ( className , styleObj )
18+ }
19+ return classMapValueCache . get ( className )
20+ }
21+
22+ let dimensionsInfoInitialized = false
23+ function useDimensionsInfo ( dimensions ) {
24+ dimensionsInfoInitialized = true
1225 if ( typeof Mpx . config . rnConfig ?. customDimensions === 'function' ) {
1326 dimensions = Mpx . config . rnConfig . customDimensions ( dimensions ) || dimensions
1427 }
15- width = dimensions . screen . width
16- height = dimensions . screen . height
28+ global . __mpxAppDimensionsInfo . window = dimensions . window
29+ global . __mpxAppDimensionsInfo . screen = dimensions . screen
1730}
1831
19- Dimensions . addEventListener ( 'change' , customDimensions )
32+ function getPageSize ( window = global . __mpxAppDimensionsInfo . screen ) {
33+ return window . width + 'x' + window . height
34+ }
35+
36+ Dimensions . addEventListener ( 'change' , ( { window, screen } ) => {
37+ const oldScreen = getPageSize ( global . __mpxAppDimensionsInfo . screen )
38+ useDimensionsInfo ( { window, screen } )
39+
40+ // 对比 screen 高宽是否存在变化
41+ if ( getPageSize ( screen ) === oldScreen ) return
2042
43+ global . __classCaches ?. forEach ( cache => cache ?. clear ( ) )
44+
45+ // 更新全局和栈顶页面的标记,其他后台页面的标记在show之后更新
46+ global . __mpxSizeCount ++
47+
48+ const navigation = getFocusedNavigation ( )
49+
50+ if ( navigation ) {
51+ global . __mpxPageSizeCountMap [ navigation . pageId ] = global . __mpxSizeCount
52+ if ( hasOwn ( global . __mpxPageStatusMap , navigation . pageId ) ) {
53+ global . __mpxPageStatusMap [ navigation . pageId ] = `resize${ global . __mpxSizeCount } `
54+ }
55+ }
56+ } )
57+
58+ // TODO: 1 目前测试鸿蒙下折叠屏screen固定为展开状态下屏幕尺寸,仅window会变化,且window包含状态栏高度
59+ // TODO: 2 存在部分安卓折叠屏机型在折叠/展开切换时,Dimensions监听到的width/height尺寸错误,并触发多次问题
2160function rpx ( value ) {
61+ const screenInfo = global . __mpxAppDimensionsInfo . screen
2262 // rn 单位 dp = 1(css)px = 1 物理像素 * pixelRatio(像素比)
2363 // px = rpx * (750 / 屏幕宽度)
24- return value * width / 750
64+ return value * screenInfo . width / 750
2565}
2666function vw ( value ) {
27- return value * width / 100
67+ const screenInfo = global . __mpxAppDimensionsInfo . screen
68+ return value * screenInfo . width / 100
2869}
2970function vh ( value ) {
30- return value * height / 100
71+ const screenInfo = global . __mpxAppDimensionsInfo . screen
72+ return value * screenInfo . height / 100
3173}
3274
3375const unit = {
@@ -38,8 +80,14 @@ const unit = {
3880
3981const empty = { }
4082
41- function formatValue ( value ) {
42- if ( width === undefined ) customDimensions ( rawDimensions )
83+ function formatValue ( value , unitType ) {
84+ if ( ! dimensionsInfoInitialized ) useDimensionsInfo ( global . __mpxAppDimensionsInfo )
85+ if ( unitType === 'hairlineWidth' ) {
86+ return StyleSheet . hairlineWidth
87+ }
88+ if ( unitType && typeof unit [ unitType ] === 'function' ) {
89+ return unit [ unitType ] ( + value )
90+ }
4391 const matched = unitRegExp . exec ( value )
4492 if ( matched ) {
4593 if ( ! matched [ 2 ] || matched [ 2 ] === 'px' ) {
@@ -180,29 +228,58 @@ function isNativeStyle (style) {
180228 )
181229}
182230
231+ function getMediaStyle ( media ) {
232+ if ( ! media || ! media . length ) return { }
233+ const { width } = global . __mpxAppDimensionsInfo . screen
234+ return media . reduce ( ( styleObj , item ) => {
235+ const { options = { } , value = { } } = item
236+ const { minWidth, maxWidth } = options
237+ if ( ! isNaN ( minWidth ) && ! isNaN ( maxWidth ) && width >= minWidth && width <= maxWidth ) {
238+ Object . assign ( styleObj , value )
239+ } else if ( ! isNaN ( minWidth ) && width >= minWidth ) {
240+ Object . assign ( styleObj , value )
241+ } else if ( ! isNaN ( maxWidth ) && width <= maxWidth ) {
242+ Object . assign ( styleObj , value )
243+ }
244+ return styleObj
245+ } , { } )
246+ }
247+
183248export default function styleHelperMixin ( ) {
184249 return {
185250 methods : {
251+ __getSizeCount ( ) {
252+ return global . __mpxPageSizeCountMap [ this . __pageId ]
253+ } ,
186254 __getClass ( staticClass , dynamicClass ) {
187255 return concat ( staticClass , stringifyDynamicClass ( dynamicClass ) )
188256 } ,
189257 __getStyle ( staticClass , dynamicClass , staticStyle , dynamicStyle , hide ) {
190258 const isNativeStaticStyle = staticStyle && isNativeStyle ( staticStyle )
191259 let result = isNativeStaticStyle ? [ ] : { }
192- const mergeResult = isNativeStaticStyle ? ( o ) => result . push ( o ) : ( o ) => Object . assign ( result , o )
193-
194- const classMap = this . __getClassMap ?. ( ) || { }
195- const appClassMap = global . __getAppClassMap ?. ( ) || { }
260+ const mergeResult = isNativeStaticStyle ? ( ...args ) => result . push ( ...args ) : ( ...args ) => Object . assign ( result , ...args )
261+ // 使用一下 __getSizeCount 触发其 get
262+ this . __getSizeCount ( )
196263
197264 if ( staticClass || dynamicClass ) {
198265 // todo 当前为了复用小程序unocss产物,暂时进行mpEscape,等后续正式支持unocss后可不进行mpEscape
199266 const classString = mpEscape ( concat ( staticClass , stringifyDynamicClass ( dynamicClass ) ) )
267+
200268 classString . split ( / \s + / ) . forEach ( ( className ) => {
201- if ( classMap [ className ] ) {
202- mergeResult ( classMap [ className ] )
203- } else if ( appClassMap [ className ] ) {
204- // todo 全局样式在每个页面和组件中生效,以支持全局原子类,后续支持样式模块复用后可考虑移除
205- mergeResult ( appClassMap [ className ] )
269+ let localStyle , appStyle
270+ const getAppClassStyle = global . __getAppClassStyle || noop
271+ if ( localStyle = this . __getClassStyle ( className ) ) {
272+ if ( localStyle . _media ?. length ) {
273+ mergeResult ( localStyle . _default , getMediaStyle ( localStyle . _media ) )
274+ } else {
275+ mergeResult ( localStyle . _default )
276+ }
277+ } else if ( appStyle = getAppClassStyle ( className ) ) {
278+ if ( appStyle . _media ?. length ) {
279+ mergeResult ( appStyle . _default , getMediaStyle ( appStyle . _media ) )
280+ } else {
281+ mergeResult ( appStyle . _default )
282+ }
206283 } else if ( isObject ( this . __props [ className ] ) ) {
207284 // externalClasses必定以对象形式传递下来
208285 mergeResult ( this . __props [ className ] )
0 commit comments