只是改名,不是重写
你有一个能跑的网页。它能渲染、能发请求、能存 token、能监听滚动。要把它装进小程序运行时,你不是把它扔掉——而是重新映射。逻辑大部分能留,它运行的那层表面变了。坑在于以为浏览器还在底下。其实不在:没有 document、没有 window、没有 localStorage 全局、也没有你能随便戳的 <div>。下面这张地图让迁移变得可预期。
生命周期:事件变成回调
在 Web 上你依赖 DOMContentLoaded、load、visibilitychange。小程序的页面是一个 Page() 对象,生命周期是一组具名回调:
Page({
onLoad(query) { /* 仅一次,首次创建时——在此读路由参数 */ },
onShow() { /* 每次页面出现,含从子页面返回 */ },
onReady() { /* 首次渲染完成,查布局从此安全 */ },
onHide() { /* 进入后台或被导航走 */ },
onUnload() { /* 销毁——在此清理定时器 */ },
})
最大的行为差异:onShow 从子页面返回时也会触发,所以那些必须反映下游改动的列表页要在 onShow 重新拉取——而不只是 onLoad。应用级事件(onLaunch、onShow、onHide)在 App() 里。没有 beforeunload 弹窗;要拦截,就去拦导航调用本身。
视图:HTML/CSS 变成 WXML/WXSS
HTML 变成 WXML——带 {{ }} 绑定、没有你能遍历的 DOM 的模板。你不再 document.querySelector 然后改节点;而是调 this.setData({ key: value }),渲染层自己 diff。这一条规则消灭了一整类布局 bug,但也干掉了任何"假定能伸进节点树"的代码。
WXSS 是 CSS 加两个会咬人的改动:新单位 rpx,750rpx 等于屏幕宽度(所以 375px 设计稿 → 750rpx,按设备自动缩放);以及被削窄的选择器集——没有相邻选择器、没有属性选择器,伪类也少得多(last-child 没了)。样式保持扁平、基于 class。
网络:fetch 变成 wx.request
这是大多数迁移卡住的地方。wx.request 不是 fetch:
| 关注点 | Web(fetch) | 小程序(wx.request) |
|---|---|---|
| 传输 | HTTP/HTTPS,任意主机 | 仅 HTTPS/WSS,主机须在白名单 |
| 域名 | 无 | 服务端域名白名单,控制台配置;localhost/IP 被拦 |
| 并发 | 浏览器限制 | request/upload/download 最大并发 10 |
| 超时 | 每次调用 | 默认与最大均 60s,可在 app.json 配置 |
| Referrer | 浏览器设定 | 固定平台格式,不可自定义 |
| 后台 | 继续 | 后台 5s 未结束回调 fail interrupted |
白名单是最经典的墙:在开发者工具关掉域名校验时能通的请求,体验版/正式版在域名未登记、未备案前一律失败。把 wx.request 包一层 Promise 做请求头、token 注入和 401 处理——和你对 fetch 做的一样,但要为 10 连接上限规划队列。
存储与状态
localStorage 变成 wx.setStorageSync / wx.getStorageSync,上限 10MB。sessionStorage 没有直接等价——短命的那点状态用路由参数或全局 getApp().globalData。别假定冷启动后的持久化是瞬时的;UI 能容忍的地方就用异步读。
当 Web API 没有孪生兄弟
有些浏览器能力干脆不在,迁移计划必须点名它们:
- 定位 —
navigator.geolocation→wx.getLocation(需 scope 授权)。 - 媒体 / 直播 — WebRTC 不可用;用原生
<live-pusher>/<live-player>组件。 - 地图、相机、视频 — 原生组件
<map>、<camera>、<video>替代 HTML 元素,且位于渲染层之上。 - Cookie / 同源 — 没有浏览器那种与后端共享的 Cookie 罐;鉴权靠你自己注入请求头的 token。
- 文件系统 — 没有任意 FS;用
wx.getFileSystemManager操作给你的沙箱。
Cross Mini App 的角色
Cross Mini App 给你一个已经会说这套表面的运行时——wx.* 对齐、rpx 布局、10 连接模型、白名单语义——于是移植后的 H5 变成 catalog 里的一个条目,而不是一次重做平台的项目。你保留业务逻辑,把"浏览器形状"的边缘换成"运行时形状"的边缘,然后装进用户已经在用的宿主 App。迁移是一张地图,不是一道悬崖。