fix(rn): 修复响应式样式尺寸更新并支持配置计算基准 - #2418
mackwang112 wants to merge 20 commits into
Conversation
# Conflicts: # packages/webpack-plugin/lib/react/processScript.js
Integrate PR #2485 and address its review feedback.
hiyuki
left a comment
There was a problem hiding this comment.
补充两个通过最小用例复现的问题。当前提交原有相关 92 项测试通过,但以下场景尚未覆盖。
|
基于提交 1. [P1] customDimensions 内读取系统信息会导致初始化栈溢出位置:packages/api-proxy/src/platform/api/system/rnSystem.js:6 如果业务在 例如: mpx.config.rnConfig.customDimensions = dimensions => {
const { statusBarHeight } = mpx.getWindowInfo()
dimensions.window.height -= statusBarHeight
return dimensions
}建议为自定义尺寸计算期间的系统信息读取提供原始尺寸路径,避免重入。 2. [P2] 媒体查询的 !important 错误覆盖后续声明位置:packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js:274–277 @media (min-width: 300px) {
.box { width: 200px !important; }
}
.box { width: 100px !important; }窗口宽度为 360 时,应由后面的声明得到 验证
|
| } | ||
|
|
||
| // 使用不可枚举属性记录窗口尺寸依赖,避免该内部标记被合并到 RN 样式中 | ||
| Object.defineProperty(styleObj, '_dependentWindowSize', { |
There was a problem hiding this comment.
正常赋值合并后移除吧,和_inlineLayer的处理方式保持一致
| dependentWindowSize = dependentWindowSize || appStyle._dependentWindowSize | ||
| } else if (global.__externalClasses?.includes(className)) { | ||
| // 始终读取版本号,确保 externalClasses 从无到有时也能触发样式重算。 | ||
| trackExternalClassesVersion(this.__mpxProxy.externalClassesState) |
There was a problem hiding this comment.
封装一个methods叫this.__trackExternalClassesVersion()吧,和this.__trackPageSizeCount()保持一致
| } | ||
|
|
||
| const proxy = instance.__mpxProxy = new MpxProxy(rawOptions, instance) | ||
| proxy.externalClassesState = reactive({ version: 0 }) |
There was a problem hiding this comment.
改成proxy.externalClassesVersion = ref(0)吧
| } | ||
|
|
||
| function isExternalClassesChanged (oldProps, newProps) { | ||
| return global.__externalClasses?.some(name => !Object.is(oldProps[name], newProps[name])) |
There was a problem hiding this comment.
propsRef的初始值是个null,不会报错么?
哦这里靠isFirst做了一层保护,但是感觉比较隐式,把propsRef的初始值改为空对象吧
There was a problem hiding this comment.
参数顺序改为 props, oldProps吧,比较符合常规,以及加一个前置判断hasOwn(props, externalClass)吧
背景
React Native 端此前基于
Dimensions.get('screen')计算rpx、vw、vh和媒体查询。在分屏、折叠屏、横竖屏切换等窗口尺寸发生变化但物理屏幕尺寸不变的场景中,响应式样式可能不会按当前页面窗口更新;后台页面重新显示时也可能保留旧窗口下的样式。直接切换为 Window 可能改变存量项目的布局效果,因此本次新增
rnConfig.dimensionsBase配置:默认使用'window',需要保持旧行为时可显式设置为'screen'。本次更新
rpx、vw、vh和媒体查询默认使用 Window 作为计算基准:rpx = value * window.width / 750vw = value * window.width / 100vh = value * window.height / 100rnConfig.dimensionsBase: 'window' | 'screen',默认值为'window';响应式单位、媒体查询、onResize和deviceOrientation使用相同的尺寸基准。notifyDimensionsChange(dimensions?)全局方法:支持宿主主动通知尺寸变化;不传参数时重新读取 React Native Dimensions,并重新执行customDimensions。getStyleDimensions(),统一返回经过customDimensions处理、并由dimensionsBase选中的当前尺寸副本。rnConfig.customDimensions处理后的有效尺寸判断是否需要刷新。formatValue路径的尺寸依赖标记,确保使用响应式单位的组件能够订阅并刷新。customDimensions的问题。@media (min-width: 600px) and (max-width: 900px)在宽度处于[600, 900]时生效。onShow、onHide或onResize。问题场景示例
以下示例均使用默认配置
dimensionsBase: 'window';设置为'screen'时,响应式单位、媒体查询、onResize和deviceOrientation均改用 Screen。1. 动态 rpx/vw/vh 未随 Window 更新
修复前: 分屏、折叠或旋转导致 Window 变化但 Screen 不变时,不会触发尺寸版本更新;同时动态
formatValue路径没有标记尺寸依赖,组件可能继续显示旧的rpx/vw/vh尺寸。修复后: 默认配置下,
600rpx、50vw和100vh立即按新 Window 尺寸重新计算,240px保持不变;配置为'screen'时继续按 Screen 尺寸计算。2. 仅使用媒体查询的组件未刷新
修复前: media 声明会被同时写入基础样式,导致宽度小于
600px时也可能直接显示绿色520px;并且仅使用媒体查询不会建立尺寸依赖,跨过断点时组件可能不刷新。修复后: 所选尺寸跨过
600px时立即在红色280px和绿色520px之间切换,无需依赖其他rpx/vw/vh样式触发刷新。3. min-width 与 max-width 组合查询范围错误
修复前: 两个条件未作为交集处理。宽度大于
900px时会被min-width分支命中,宽度小于600px时会被max-width分支命中,因此该示例在区间外也会错误显示绿色520px。修复后: 仅当
600px <= 所选尺寸.width <= 900px时使用绿色520px,区间外使用红色280px,两个边界均包含。4. 后台页面返回后仍使用旧尺寸
复现步骤:宽屏进入页面后跳转到下一页,在下一页切换为窄屏再返回。
修复前: 没有声明页面生命周期的后台页面不会监听 show,页面尺寸版本未追平全局版本,返回后
600rpx和80vw仍可能保持宽屏下的旧宽度。修复后: 返回页面时会先同步尺寸版本,
600rpx和80vw立即按当前计算基准重新计算,240px保持不变。600rpx与80vw按公式本来就相等。5. 纯媒体查询首次计算未应用 customDimensions
修复前: 如果组件没有
rpx、vw或vh,首次媒体查询计算可能直接使用未经customDimensions处理的原始尺寸,结果还会受到其他组件渲染顺序影响。修复后: 媒体查询读取尺寸前会确保
customDimensions已执行,首次渲染即可使用正确的有效尺寸。notifyDimensionsChange 与 #2485 review 修复
dimensionsBase选择 Window 或 Screen 作为刷新判断基准。onResize与deviceOrientation使用相同基准:Window 模式只响应 Window 尺寸变化,Screen 模式只响应 Screen 尺寸变化。customDimensions原地修改 React Native 返回的对象。customDimensions”的问题。getStyleDimensions
customDimensions处理的原始尺寸。customDimensions,下次读取会基于最近一次原始 Dimensions 重新处理。其他已有修复
修复组件销毁后导致 rpx/vw/vh 响应式单位失效
现状:页面上的组件销毁后,尺寸变化可能不再触发使用响应式单位的组件刷新。
原因:
del(global.__mpxPageSizeCountMap, pageId)应只在页面销毁时触发,此前组件销毁时也会触发。尺寸变化时仅刷新依赖响应式单位的组件
由刷新所有组件改为仅刷新依赖
rpx、vw、vh或媒体查询的组件。修复 RN externalClasses 变化时未触发组件 render
externalClasses配置保留到运行时并加入validProps,使其与普通 props 一样具有响应性。__getStyle从this.__mpxProxy.props[className]获取 externalClasses,使样式计算与响应式数据建立关联。验证
./node_modules/.bin/jest packages/core/__tests__/common/dimensionsHelper.spec.js packages/core/__tests__/common/styleHelperMixin.ios.spec.js packages/webpack-plugin/test/platform/wx/style/style-rn.spec.js --runInBand --watchman=false:3 suites、92 tests passed。npm run build:tsc通过。rpx/vw/vh、固定px对照、纯媒体查询、范围媒体查询,以及后台页面宽屏切换窄屏后返回的场景。