Skip to content

微信扫码登录 UI 深度定制实践

1. 业务背景

在自研登录页中,为了使微信扫码插件(Iframe)与整体品牌视觉(UI/UX)高度融合,我们需要克服微信官方插件的样式限制。

核心目标

  • 视觉对齐:使二维码容器符合 214px x 214px 的设计稿尺寸。
  • 样式自定义:实现圆角边框、遮罩协议层,并去除微信原生冗余文字。
  • 布局稳定:确保 Header(标题)、Iframe(中间主体)与 Footer(操作提示)在不同状态下保持"相对静止",不产生视觉抖动。

2. 核心挑战与破解方案

2.1 跨域样式注入失效

  • 挑战:由于同源策略,无法直接通过 JS 修改 Iframe 内部 DOM;且当开启 stylelite=1(轻量化模式)时,微信官方提供的 href 参数(Base64 CSS)不生效。
  • 方案容器裁切与比例缩放(Visual Masking & Scaling)
    • 视窗逻辑:外层容器 wx-iframe-wrapper 设置 overflow: hidden 作为"面罩"。
    • 比例计算:微信内部二维码区域固定为 160px,目标容器为 214px。通过 $214 \div 160 \approx 1.3375$ 的缩放比例,将内部二维码放大填满视窗。
    • 位置修正:通过 padding-left: 7px 补偿微信原生布局的偏置,实现视觉居中。

2.2 布局动态偏移问题

  • 挑战:常规使用 margin 控制 Header、Footer 与中间 Iframe 的间距。但由于 Iframe 加载是异步的,且 stylelite 模式下的高度可能微变,容易导致上下元素被挤压或产生位移。
  • 方案固定高度 + Flex 弹性布局
    • 高度锁定:父容器 .wx-qrcode-login 设置固定高度 314px
    • 弹性分布:使用 display: flex; flex-direction: column; justify-content: space-between;
    • 优势:Header 始终贴顶,Footer 始终贴底,中间部分自动填充。无论 Iframe 加载状态如何,整体 UI 的骨架保持"相对静止",彻底消除了布局抖动。

3. 技术实现细节 (Code Snippets)

3.1 完美布局模型

scss
.wx-qrcode-login {
  height: 314px;              // 锁定整体高度,防止被内部挤压
  display: flex;
  flex-direction: column;
  justify-content: space-between; // 核心:Header/主体/Footer 三点布局,无需 Margin

  .wx-iframe-wrapper {
    width: 214px;
    height: 214px;
    overflow: hidden;         // 裁切多余白边
    box-sizing: border-box;   // 怪异盒模型,确保 Border 不撑大容器
    border-radius: 10px;      // 视觉美化
    padding-left: 7px;        // 修正二维码中心点

    .wx-iframe {
      width: 180px;
      height: 160px;          // 微信原始比例
      transform: scale(1.3375); // 比例变换实现"充满"效果
      transform-origin: center center;
    }
  }
}

3.2 授权回调页面的反向缩放

  • 挑战:由于外层 Iframe 使用了 scale(1.3375) 放大处理,当微信授权完成后跳转到回调页面(如 WxLogin.vueWxBind.vue)时,页面内容也会被同比例放大,导致文字和图标过大、布局溢出。
  • 方案反向缩放补偿(Inverse Scaling)
    • 计算公式:$1 \div 1.3375 \approx 0.7477$
    • 实现方式:在回调页面的根容器上应用反向缩放,抵消父级 Iframe 的放大效果。
scss
.auth-container-box {
  position: fixed;
  top: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  // 当前页面为内嵌到 iframe 的微信授权回调页,iframe 整体进行了放大,这里需要提前缩小
  // 参考:resources/components/auth/components/wxQrCodeLogin.vue
  // 1 ÷ 1.3375 = 0.7477400972
  transform: scale(0.7477);
  transform-origin: center center;
}
  • 适用页面
    • WxLogin.vue - 微信登录授权回调页
    • WxBind.vue - 微信绑定授权回调页

3.3 逻辑控制与安全兜底

通过 Vue 的 computed 属性,将二维码显示与业务协议勾选逻辑(isAgree)强绑定,并确保在 PC 模式下禁用快速登录,维持二维码显示的一致性。

typescript
const currentUrl = `...&stylelite=1&fast_login=0&#wechat_redirect`

const iframeDisplay = computed(() => {
  // 业务逻辑:只有在绑定页或已同意协议时才加载 Iframe
  if(window.location.pathname === '/bind') return true
  return isAgree.value
})

4. 关键发现:fast_login 依赖项

在实践中发现,该方案高度依赖于参数 fast_login=0

  • 如果不禁用(=1):微信会尝试显示"快速登录"按钮。由于按钮界面是长方形布局且包含交互点击,当前的正方形裁切pointer-events: none(如果使用)会导致按钮被遮挡或无法点击,导致登录流程中断。
  • 结论:在需要高度自定义 UI 的场景下,必须保持 fast_login=0 以确保输出内容为可预测的正方形二维码。

5. 方案总结

本方案通过 CSS 几何变换 解决了跨域样式难题,通过 Flex 空间分布 解决了布局稳定性难题。

优化维度传统方案本方案
样式控制依赖官方参数(不稳定)容器裁切 + Scale 缩放(完全自主)
布局稳定性Margin 撑开(易抖动)固定高度 + Space-between(绝对静止)
盒子模型Content-box(计算复杂)Border-box(尺寸精准)
回调页适配内容被放大溢出反向缩放补偿(视觉还原)
用户体验微信原生水印、文字干扰纯净二维码显示

基于 VitePress 构建