fix(ui): 根治真机弹窗 fixed 降级(移出 .container + pageIn 去 transform)

根因:.page-enter 的 pageIn 动画含 transform,即使 to: transform:none,
真机 fill-mode 没真正消除 transform,.container 仍是 fixed 的包含块。
记录页内容超一屏时 mask 降级相对 .container(高>>视口),flex 居中把
弹窗放到 .container 中心(视口外),真机看不到(模拟器宽松所以正常)。

- records: 日历详情弹窗移出 .container.page-enter,fixed 相对视口;
  加 style themeStyle 拿暗黑变量
- app.wxss: pageIn keyframes 去掉 transform 只留 opacity 淡入,根治所有
  页面(settings 计划编辑器/timer 完成弹窗)的 fixed 降级
- calendar-heatmap: onDayTap 的 find 用 Number(day) 修真机 dataset
  字符串化导致 === 失败;移除诊断日志

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-09 14:41:34 +08:00
parent 7784ccafa8
commit afd2b72bcb
3 changed files with 20 additions and 16 deletions
+8 -7
View File
@@ -129,11 +129,12 @@ image {
} }
@keyframes pageIn { @keyframes pageIn {
from { opacity: 0; transform: translateY(20rpx); } /* Opacity-only: any transform (even translateY(0) held by animation
/* `none` (not translateY(0)) so the finished animation leaves NO transform fill-mode) makes .container a containing block that demotes descendant
on .container - any non-none transform creates a containing block that position:fixed to relative-to-container, breaking full-screen modals on
demotes descendant position:fixed to relative-to-container, breaking real devices once the page scrolls past one viewport. The prior
full-screen modals (day-detail / plan-editor / completion) once the `to: transform: none` did NOT hold on real devices, so drop transform
page scrolls past one viewport height. */ from the keyframes entirely. Pages still get a fade-in. */
to { opacity: 1; transform: none; } from { opacity: 0; }
to { opacity: 1; }
} }
@@ -79,13 +79,16 @@ Component({
onDayTap(e) { onDayTap(e) {
const day = e.currentTarget.dataset.day const day = e.currentTarget.dataset.day
if (!day) return if (!day && day !== 0) return
const cell = this.data.weeks.flat().find(c => c && c.day === day) // dataset values can arrive as strings on real devices, which breaks
// the strict === against c.day (number). Normalize so the lookup
// works on both simulator and device.
const cell = this.data.weeks.flat().find(c => c && c.day === Number(day))
if (!cell || cell.duration <= 0) return if (!cell || cell.duration <= 0) return
this.triggerEvent('daytap', { this.triggerEvent('daytap', {
year: this.properties.year, year: this.properties.year,
month: this.properties.month, month: this.properties.month,
day, day: cell.day,
duration: cell.duration duration: cell.duration
}) })
} }
+6 -6
View File
@@ -113,11 +113,12 @@
</view> </view>
<!-- /hidden wrapper --> <!-- /hidden wrapper -->
<!-- 日期详情弹窗:普通 view 实现,不用 ui-modal。 </view>
自定义组件根元素的 position: fixed 会被小程序运行时吞掉,叠加 <!-- 日期详情弹窗:放在 .container 外。 .page-enter 的 transform 让 .container
.page-enter 的 transform 会让 fixed 降级相对 .container,导致弹窗 成为 fixed 的包含块,mask 降级相对 .container(高>>视口),body 居中到
落到容器末尾而非视口居中。普通 view 的 fixed 100% 生效。 --> .container 中心(视口外),真机看不到。移到 .container 外,fixed 相对视口;
<view wx:if="{{showDayDetail}}" class="day-detail-mask" catchtouchmove="onNoop"> style 注入 themeStyle 拿暗黑变量。 -->
<view wx:if="{{showDayDetail}}" class="day-detail-mask" style="{{themeStyle}}" catchtouchmove="onNoop">
<view class="day-detail-mask__bg" bindtap="onCloseDayDetail"></view> <view class="day-detail-mask__bg" bindtap="onCloseDayDetail"></view>
<view class="day-detail-body" catchtap="onNoop"> <view class="day-detail-body" catchtap="onNoop">
<view class="detail-date-row"> <view class="detail-date-row">
@@ -146,4 +147,3 @@
</view> </view>
</view> </view>
</view> </view>
</view>