Skip to content

fix(rn): 修复响应式样式尺寸更新并支持配置计算基准 - #2418

Open
mackwang112 wants to merge 20 commits into
masterfrom
fix-resize
Open

mackwang112 wants to merge 20 commits into
masterfrom
fix-resize

Conversation

@mackwang112

@mackwang112 mackwang112 commented Jan 29, 2026

Copy link
Copy Markdown
Collaborator

背景

React Native 端此前基于 Dimensions.get('screen') 计算 rpxvwvh 和媒体查询。在分屏、折叠屏、横竖屏切换等窗口尺寸发生变化但物理屏幕尺寸不变的场景中,响应式样式可能不会按当前页面窗口更新;后台页面重新显示时也可能保留旧窗口下的样式。

直接切换为 Window 可能改变存量项目的布局效果,因此本次新增 rnConfig.dimensionsBase 配置:默认使用 'window',需要保持旧行为时可显式设置为 'screen'

mpx.config.rnConfig.dimensionsBase = 'screen'

本次更新

  • rpxvwvh 和媒体查询默认使用 Window 作为计算基准:
    • rpx = value * window.width / 750
    • vw = value * window.width / 100
    • vh = value * window.height / 100
  • 新增 rnConfig.dimensionsBase: 'window' | 'screen',默认值为 'window';响应式单位、媒体查询、onResizedeviceOrientation 使用相同的尺寸基准。
  • 合并 PR feat: RN 新增 notifyDimensionsChange 配置,支持手动触发 dimensions 更新 #2485notifyDimensionsChange(dimensions?) 全局方法:支持宿主主动通知尺寸变化;不传参数时重新读取 React Native Dimensions,并重新执行 customDimensions
  • 新增全局 getStyleDimensions(),统一返回经过 customDimensions 处理、并由 dimensionsBase 选中的当前尺寸副本。
  • 所选尺寸发生变化时,以经过 rnConfig.customDimensions 处理后的有效尺寸判断是否需要刷新。
  • 补全动态 formatValue 路径的尺寸依赖标记,确保使用响应式单位的组件能够订阅并刷新。
  • 修复纯媒体查询声明泄漏到基础样式的问题。
  • 修复纯媒体查询首次计算前未执行 customDimensions 的问题。
  • 修复组合媒体查询的匹配逻辑;@media (min-width: 600px) and (max-width: 900px) 在宽度处于 [600, 900] 时生效。
  • 所选尺寸发生变化时清理 class 样式缓存,并只触发依赖尺寸的组件重新渲染。
  • 页面重新显示时同步页面尺寸版本,使后台页面在宽屏切换为窄屏后返回时能立即使用当前尺寸对应的样式;该同步不依赖页面是否声明 onShowonHideonResize
  • 补充相关类型、文档及 Mpx2RN Skill 说明。

问题场景示例

以下示例均使用默认配置 dimensionsBase: 'window';设置为 'screen' 时,响应式单位、媒体查询、onResizedeviceOrientation 均改用 Screen。

1. 动态 rpx/vw/vh 未随 Window 更新

<view wx:style="{{rpxStyle}}"></view>
<view wx:style="{{vwStyle}}"></view>
<view wx:style="{{pxStyle}}"></view>
createComponent({
  data: {
    rpxStyle: { width: '600rpx' },
    vwStyle: { width: '50vw' },
    pxStyle: { width: '240px' },
    vhStyle: { height: '100vh' }
  }
})

修复前: 分屏、折叠或旋转导致 Window 变化但 Screen 不变时,不会触发尺寸版本更新;同时动态 formatValue 路径没有标记尺寸依赖,组件可能继续显示旧的 rpx/vw/vh 尺寸。

修复后: 默认配置下,600rpx50vw100vh 立即按新 Window 尺寸重新计算,240px 保持不变;配置为 'screen' 时继续按 Screen 尺寸计算。

2. 仅使用媒体查询的组件未刷新

.media-box {
  width: 280px;
  background-color: red;
}

@media (min-width: 600px) {
  .media-box {
    width: 520px;
    background-color: green;
  }
}

修复前: media 声明会被同时写入基础样式,导致宽度小于 600px 时也可能直接显示绿色 520px;并且仅使用媒体查询不会建立尺寸依赖,跨过断点时组件可能不刷新。

修复后: 所选尺寸跨过 600px 时立即在红色 280px 和绿色 520px 之间切换,无需依赖其他 rpx/vw/vh 样式触发刷新。

3. min-width 与 max-width 组合查询范围错误

.range-box {
  width: 280px;
  background-color: red;
}

@media (min-width: 600px) and (max-width: 900px) {
  .range-box {
    width: 520px;
    background-color: green;
  }
}

修复前: 两个条件未作为交集处理。宽度大于 900px 时会被 min-width 分支命中,宽度小于 600px 时会被 max-width 分支命中,因此该示例在区间外也会错误显示绿色 520px

修复后: 仅当 600px <= 所选尺寸.width <= 900px 时使用绿色 520px,区间外使用红色 280px,两个边界均包含。

4. 后台页面返回后仍使用旧尺寸

<view class="rpx-bar"></view>
<view class="vw-bar"></view>
<view class="px-bar"></view>
// 页面刻意不声明 onShow / onHide / onResize
createPage({})
.rpx-bar { width: 600rpx; }
.vw-bar { width: 80vw; }
.px-bar { width: 240px; }

复现步骤:宽屏进入页面后跳转到下一页,在下一页切换为窄屏再返回。

修复前: 没有声明页面生命周期的后台页面不会监听 show,页面尺寸版本未追平全局版本,返回后 600rpx80vw 仍可能保持宽屏下的旧宽度。

修复后: 返回页面时会先同步尺寸版本,600rpx80vw 立即按当前计算基准重新计算,240px 保持不变。600rpx80vw 按公式本来就相等。

5. 纯媒体查询首次计算未应用 customDimensions

mpx.config.rnConfig.customDimensions = (dimensions) => {
  dimensions.window.width /= 2
  return dimensions
}
@media (min-width: 600px) {
  .media-box { width: 520px; }
}

修复前: 如果组件没有 rpxvwvh,首次媒体查询计算可能直接使用未经 customDimensions 处理的原始尺寸,结果还会受到其他组件渲染顺序影响。

修复后: 媒体查询读取尺寸前会确保 customDimensions 已执行,首次渲染即可使用正确的有效尺寸。

vh 示例只验证所选尺寸的高度计算;非 custom navigation 下 100vh 是否扣除原生导航栏不在本次修改范围内。

notifyDimensionsChange 与 #2485 review 修复

// 重新读取当前 React Native Dimensions
notifyDimensionsChange()

// 或显式传入尺寸
notifyDimensionsChange({
  window: nextWindow,
  screen: nextScreen
})
  • 手动通知与原生 Dimensions change 事件复用同一更新流程,并按 dimensionsBase 选择 Window 或 Screen 作为刷新判断基准。
  • onResizedeviceOrientation 使用相同基准:Window 模式只响应 Window 尺寸变化,Screen 模式只响应 Screen 尺寸变化。
  • 调用入口会复制原始 Dimensions,避免 customDimensions 原地修改 React Native 返回的对象。
  • 所有尺寸应用入口都会统一维护初始化状态,修复“首次样式计算前已收到通知,随后重复执行 customDimensions”的问题。

getStyleDimensions

const dimensions = getStyleDimensions()
console.log(dimensions.width, dimensions.height)
  • 首次调用会确保尺寸完成初始化,避免其他调用方读到未经 customDimensions 处理的原始尺寸。
  • 如果在首次读取后才配置或替换 customDimensions,下次读取会基于最近一次原始 Dimensions 重新处理。
  • 返回的是尺寸副本,调用方修改返回值不会污染响应式样式使用的内部缓存。

其他已有修复

修复组件销毁后导致 rpx/vw/vh 响应式单位失效

现状:页面上的组件销毁后,尺寸变化可能不再触发使用响应式单位的组件刷新。

原因:del(global.__mpxPageSizeCountMap, pageId) 应只在页面销毁时触发,此前组件销毁时也会触发。

尺寸变化时仅刷新依赖响应式单位的组件

由刷新所有组件改为仅刷新依赖 rpxvwvh 或媒体查询的组件。

修复 RN externalClasses 变化时未触发组件 render

  • externalClasses 配置保留到运行时并加入 validProps,使其与普通 props 一样具有响应性。
  • __getStylethis.__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。
  • 相关文件 ESLint 检查通过。
  • npm run build:tsc 通过。
  • 手动覆盖动态 rpx/vw/vh、固定 px 对照、纯媒体查询、范围媒体查询,以及后台页面宽屏切换窄屏后返回的场景。

@mackwang112
mackwang112 marked this pull request as draft January 29, 2026 13:27
@mackwang112
mackwang112 marked this pull request as ready for review March 10, 2026 07:53
@mackwang112 mackwang112 changed the title fix: 修复rpx在屏幕尺寸变化时未跟随变化 fix(rn): 修复响应式样式尺寸更新并支持配置计算基准 Sep 10, 2026
Comment thread .agents/skills/mpx2rn/references/rn-script-reference.md Outdated
Comment thread .agents/skills/mpx2rn/references/rn-style-practice.md Outdated
Comment thread .agents/skills/mpx2rn/references/rn-style-reference.md Outdated
Comment thread packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js Outdated
Comment thread packages/webpack-plugin/lib/loader.js Outdated
Comment thread packages/webpack-plugin/lib/react/style-helper.js Outdated
Comment thread packages/webpack-plugin/lib/react/style-helper.js Outdated
Comment thread packages/core/src/platform/patch/getDefaultOptions.ios.js Outdated

@hiyuki hiyuki left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

补充两个通过最小用例复现的问题。当前提交原有相关 92 项测试通过,但以下场景尚未覆盖。

Comment thread packages/webpack-plugin/lib/react/style-helper.js Outdated
Comment thread packages/core/src/platform/dimensionsHelper.js Outdated
Comment thread packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants