封面

一套智慧门禁应用的 H5 与微信小程序双端重构

写作时间:2026-07-07 00:38:00
# uni-app
# 微信小程序
# 前端
# 项目复盘

这次重构的是一套已有业务基础的智慧门禁应用。

项目原本已经具备设备开门、二维码、访客、房屋和个人中心等能力,但随着功能逐渐增加,首页的信息层级变得松散,部分页面仍保留着旧版设计。更棘手的是,同一套代码在 H5 中表现正常,进入微信小程序后却出现图片空白、二维码闪动、拖动失效和底部导航重叠等问题。

所以这次工作的重点不是推翻重写,而是在保留原有业务接口和页面路由的前提下,重新整理用户体验,并逐一处理跨端差异。

先重新划分首页的主次

新版首页保留了三个主要层级:

  1. 顶部的社区切换
  2. 大面积广告内容
  3. 当前可操作的门禁设备

广告区域没有继续使用普通轮播组件,而是实现了一套手写堆叠卡片。

页面会同时渲染当前卡片和后方的预备卡片。用户滑动时,页面主体和主视觉区域保持固定,只有当前卡片执行飞出动画,然后由下一张卡片补位。

这种实现比普通左右轮播更接近最初设计稿里的“翻卡”感觉,同时避免了手势过程中整个页面被拖着移动。

门禁区域则做了相反的处理:卡片尺寸缩小,保留左右滑动和两侧设备预览,让用户能够快速判断前后还有其他设备。

设备卡片继续承接原有业务能力:

  • 一键开门
  • 按设备能力显示二维码入口
  • 门禁排序
  • 监控视频入口
  • 设备图片和位置显示

底部导航只保留门禁和个人中心,没有在首页重复堆放个人中心已有的入口。

H5 能显示,不代表小程序也能显示

远程设备图片是这次遇到的第一个明显跨端问题。

相同的图片地址在 H5 中可以直接显示,进入微信小程序后却可能变成空白。即使关闭开发工具中的合法域名校验,问题依旧存在。

最终没有把所有图片替换成本地兜底资源,而是根据资源类型分别处理:

  • 普通远程栅格图片先通过小程序图片接口解析
  • 获取可用的临时文件路径后再交给组件显示
  • 可以被平台直接渲染的资源继续使用原地址
  • 加载确实失败时才显示通用兜底图标

这样既保留了后端设备图片,也避免 H5 和微信小程序呈现两套完全不同的视觉资源。

这里得到的经验是:开发工具里的“关闭域名校验”只能排除一类限制,不能证明远程资源已经满足小程序的解码和渲染要求。

二维码为什么会先错位再弹回来

二维码在 H5 中一直正常,但微信小程序中会先出现在弹窗之外,随后闪动并回到正确位置。

问题不在二维码内容,而在画布的生命周期。

小程序的 canvas 在弹窗布局尚未稳定时开始绘制,生成和导出过程又会触发可见区域更新。用户因此看到了二维码生成过程中的中间状态。

最后采用了双端分流方案:

  • H5 继续直接渲染二维码
  • 微信小程序在不可见区域生成二维码
  • 生成完成后导出为临时图片
  • 弹窗只显示已经完成的图片
  • 弹窗高度限制在当前视口范围内

二维码不再参与弹窗初次布局,也就不会出现先错位、再回弹的过程。

这类问题如果只调整 z-index、定位或延迟时间,很容易暂时掩盖症状。真正稳定的处理方式,是不要让用户看到画布的中间生成状态。

把门禁排序拆成两个触摸区域

门禁排序页原本同时承担列表滚动、长按排序和设备开关操作,这几个行为都依赖触摸事件,很容易互相争夺手势。

实际出现过的问题包括:

  • 拖动过程卡顿
  • 只能向下排序,无法向上排序
  • 右侧开关没有反应
  • 真机无法滚动到列表底部
  • 修改状态后无法保存
  • 保存返回首页后仍需手动刷新

最后将每一行明确拆成两个触摸区域:

  • 左侧到中间区域负责长按拖动
  • 右侧区域负责页面滚动和设备显示开关

拖动距离改用视口坐标计算,避免页面滚动抵消手指向上的移动距离。目标索引也改成正负方向对称的阈值算法,不再让向上和向下拖动使用不同的取整结果。

排序和设备开关最终共用一条批量保存路径。保存成功后写入刷新标记,返回首页时重新获取设备列表,并重新校准当前设备索引和二维码能力。

这样既避免了每次点击开关都立即请求接口,也解决了“页面看起来改了,实际没有保存”的问题。

底部导航与安全区域

首页内容较多时,门禁卡片曾经与底部导航发生重叠。

这里的问题并不只是少加了一段底部间距,而是页面内容、固定导航和设备安全区域被重复计算。部分机型有底部安全区,H5 模拟器和微信开发者工具的计算结果又不完全一致。

最终处理方式是:

  • 页面内容只负责预留底部空间
  • 导航组件负责自身层级
  • 不在多个容器中重复固定导航
  • 同时兼容不同形式的安全区域变量
  • 避免使用运行时窗口高度锁死整个页面

页面因此可以正常滚动,导航也能保持在交互层最上方。

认证页面也需要跨端检查

登录、注册和忘记密码页面统一了视觉结构,同时处理了几个容易被忽略的问题:

  • H5 宽屏模式下输入提示文字被裁切
  • 密码显示图标重复出现
  • 输入内容与占位文字重叠
  • 业主和管理员登录提示不明确
  • 服务条款默认处于勾选状态

登录页现在会根据模式显示不同的输入提示。服务条款默认保持未勾选,即使本地保存了账号信息,也不会替用户恢复“已同意”状态。

只有用户主动操作后,协议状态才会改变。

这一点看起来只是一个布尔值,但它关系到用户是否真正表达了同意,不能为了减少一次点击而自动处理。

个人中心回归业务本身

个人中心恢复并整理了当前版本需要的功能入口,包括物业服务、人员管理、房屋管理和访客能力。

这部分没有继续增加装饰性内容,而是优先保证:

  • 图标来源一致
  • H5 与小程序显示一致
  • 固定功能不依赖临时接口数据
  • 入口名称与实际业务页面对应
  • 首页与个人中心之间不重复放置相同功能

对于这类高频工具页面,清晰和稳定比视觉花样更重要。

验证比“看起来正常”更重要

跨端问题最容易出现的情况,是在一个环境中修好后,就误以为所有平台都已经正常。

这次每个关键改动都同时检查了:

  • H5 页面表现
  • 微信开发者工具编译结果
  • 微信小程序运行效果
  • 不同尺寸下的布局
  • 页面返回后的数据刷新
  • 触摸、滚动、长按和开关之间的冲突

项目还增加了针对当前重构的静态验收脚本,用于检查关键组件、交互入口和容易回归的实现细节。

它不能代替真机测试,但可以防止已经解决的问题在后续修改中悄悄回来。

最后的结果

这次重构没有改变后端业务边界,也没有重新发明已有的开门流程。

真正完成的是三件事:

  1. 重新建立首页和个人中心的信息层级
  2. 让 H5 与微信小程序尽可能呈现一致的结果
  3. 把图片、二维码、触摸排序和安全区域这些跨端问题收敛到明确的组件与流程中

回头看,最值得记录的一点是:

跨端开发中,代码复用只是起点,行为一致才是最终目标。

同一个图片地址、同一个 canvas、同一个触摸事件,在不同平台上都可能遵循不同的规则。比起不断增加局部样式和延迟,更可靠的方法仍然是找到差异发生的层级,再让每个平台走适合自己的实现路径。