微信小程序知识点

微信小程序

数据绑定

在微信小程序中,数据绑定是通过 WXML 文件中的双大括号 {{}} 语法实现的,可以将 JavaScript 文件(.js)中定义的数据动态渲染到页面上。以下是一个完整的例子:

1. 数据定义(在 .js 文件中)

js 复制代码
// app.js 或页面.js 中
Page({
  data: {
    message: "Hello Mini Program!",  // 文本数据
    showMessage: true,              // 条件渲染
    list: ["Apple", "Banana", "Orange"], // 列表数据
    count: 0                        // 动态更新数据
  },

  // 点击事件处理函数
  toggleMessage: function() {
    this.setData({
      showMessage: !this.data.showMessage // 切换布尔值
    });
  },

  // 数字递增函数
  increment: function() {
    this.setData({
      count: this.data.count + 1
    });
  }
});

2. 数据绑定(在 .wxml 文件中)

html 复制代码
<!-- 页面.wxml -->
<view>
  <!-- 1. 基础文本绑定 -->
  <text>{{message}}</text>

  <!-- 2. 条件渲染 -->
  <view wx:if="{{showMessage}}">
    <text>Message is visible!</text>
  </view>
  <view wx:else>
    <text>Message is hidden.</text>
  </view>

  <!-- 3. 列表渲染 -->
  <view wx:for="{{list}}" wx:key="index">
    <text>{{index + 1}}. {{item}}</text>
  </view>

  <!-- 4. 事件绑定更新数据 -->
  <button bindtap="toggleMessage">Toggle Message</button>
  <button bindtap="increment">Count: {{count}}</button>
</view>

3. 效果说明

  1. 文本绑定‌:页面会直接显示 "Hello Mini Program!"。

  2. 条件渲染 ‌:点击 "Toggle Message" 按钮会切换显示 Message is visible!Message is hidden.

  3. 列表渲染 ‌:自动渲染数组 ["Apple", "Banana", "Orange"],显示为:

    text 复制代码
    1. Apple
    2. Banana
    3. Orange
  4. 动态更新‌:点击 "Count" 按钮时,数字会从 0 开始递增。


核心机制

  • 数据驱动视图 ‌:通过 this.setData() 更新数据,小程序会自动重新渲染相关视图。
  • 条件与循环 ‌:wx:if 控制元素显示/隐藏,wx:for 遍历数组生成列表。
  • 事件绑定 ‌:bindtap 绑定点击事件,调用 .js 中的函数。

事件绑定

微信小程序中的事件绑定通过 ‌bindcatch 前缀实现,例如 bindtap(点击事件)、bindinput(输入事件)等。下面是一个完整的例子,涵盖常见事件类型:

1. 事件绑定示例(.wxml 文件)

html 复制代码
<!-- 页面.wxml -->
<view>
  <!-- 1. 点击事件(bindtap) -->
  <button bindtap="handleClick">点击我</button>
  <text>点击次数:{{clickCount}}</text>

  <!-- 2. 输入事件(bindinput) -->
  <input 
    bindinput="handleInput" 
    placeholder="输入内容" 
    value="{{inputText}}"
  />
  <text>输入内容:{{inputText}}</text>

  <!-- 3. 长按事件(bindlongpress) -->
  <button bindlongpress="handleLongPress">长按我</button>
  <text>{{longPressText}}</text>

  <!-- 4. 阻止事件冒泡(catchtap) -->
  <view bindtap="parentTap">
    <text>父容器(点击会触发)</text>
    <button catchtap="childTap">子按钮(点击不会冒泡)</button>
  </view>

  <!-- 5. 传递自定义参数(data-*) -->
  <button 
    bindtap="handleCustomParam" 
    data-id="123" 
    data-info="hello"
  >传递参数</button>
</view>

2. 事件处理逻辑(.js 文件)

js 复制代码
// 页面.js
Page({
  data: {
    clickCount: 0,
    inputText: "",
    longPressText: ""
  },

  // 1. 点击事件处理
  handleClick() {
    this.setData({
      clickCount: this.data.clickCount + 1
    });
  },

  // 2. 输入事件处理(实时更新输入内容)
  handleInput(e) {
    this.setData({
      inputText: e.detail.value
    });
  },

  // 3. 长按事件处理
  handleLongPress() {
    this.setData({
      longPressText: "长按触发!"
    });
  },

  // 4. 事件冒泡示例
  parentTap() {
    console.log("父容器点击事件");
  },
  childTap() {
    console.log("子按钮点击事件(不会触发父容器的tap)");
  },

  // 5. 获取自定义参数
  handleCustomParam(e) {
    const id = e.currentTarget.dataset.id; // 123
    const info = e.currentTarget.dataset.info; // "hello"
    console.log("参数:", { id, info });
  }
});

3. 效果说明

  1. 点击事件

    • 点击按钮时,clickCount 数值递增。
    • 使用 bindtap 绑定点击事件。
  2. 输入事件

    • 输入框内容实时同步到 inputText
    • 通过 e.detail.value 获取输入值。
  3. 长按事件

    • 长按按钮显示 "长按触发!"。
    • 使用 bindlongpress 绑定长按事件。
  4. 阻止事件冒泡

    • 点击子按钮时,catchtap 会阻止事件冒泡到父容器。
    • 点击父容器其他区域仍会触发 parentTap
  5. 传递自定义参数

    • 通过 data-* 属性传递参数(如 data-id)。
    • 在事件对象 e.currentTarget.dataset 中获取参数。

核心机制

  • 事件类型 ‌:常用事件包括 tap(点击)、input(输入)、longpress(长按)、touchstart(触摸开始)等。

  • 事件对象 ‌:通过 e.detail 获取事件详细信息(如输入值、坐标)。

  • 冒泡控制‌:

    • bind 允许事件冒泡(如 bindtap)。
    • catch 阻止事件冒泡(如 catchtap)。
  • 参数传递 ‌:使用 data-* 属性向事件处理函数传递自定义数据。

微信小程序的模板语法类指令

一、列表渲染指令

  1. ‌**wx:for**‌

    用于循环渲染数组或对象,默认通过 {{item}}{{index}} 访问元素及索引‌。

    html 复制代码
    <view wx:for="{{list}}">{{index}}: {{item}}</view>
  2. ‌**wx:for-item**‌

    自定义循环元素的变量名(默认 item)‌。

    html 复制代码
    <view wx:for="{{list}}" wx:for-item="book">{{book.name}}</view>
  3. ‌**wx:for-index**‌

    自定义循环索引的变量名(默认 index)‌。

  4. ‌**wx:key**‌

    指定列表项的唯一标识符(如 id*this),优化渲染性能‌。


二、条件渲染指令

  1. ‌**wx:if / wx:elif / wx:else**‌

    根据条件动态控制元素的显示与隐藏,通过条件判断直接操作 DOM 结构‌。

    html 复制代码
    <view wx:if="{{show}}">显示内容</view>
    <view wx:else>隐藏内容</view>
  2. ‌**hidden 属性**‌

    通过布尔值控制元素显隐(仅切换 CSS 的 display 属性),适用于频繁切换的场景‌。

    html 复制代码
    <view hidden="{{isHidden}}">通过 hidden 属性控制显隐</view>

三、模板定义与引用指令

  1. ‌**template 标签**‌

    定义可复用的代码片段,通过 name 属性命名模板‌。

    html 复制代码
    <template name="msgItem">
      <view>{{index}}: {{msg}}</view>
    </template>
  2. ‌**is 属性**‌

    动态引用模板,结合 data 属性传递所需数据‌。

    html 复制代码
    <template is="msgItem" data="{{...item}}" />
  3. 动态选择模板

    通过三元表达式动态渲染不同模板,例如:

    html 复制代码
    <template is="{{item % 2 === 0 ? 'even' : 'odd'}}" />

四、其他辅助指令

  1. ‌**block 标签**‌

    包裹多个元素但不渲染自身,常用于结合条件或循环指令‌。

    html 复制代码
    <block wx:if="{{flag}}">
      <view>A</view>
      <view>B</view>
    </block>

总结

指令类型 核心指令/属性 作用场景
列表渲染 wx:for, wx:key 遍历数组/对象
条件渲染 wx:if, hidden 动态控制元素显隐
模板定义与引用 template, is, data 复用代码片段
辅助标签 block 包裹多元素且不渲染自身

注意事项

  • 数据绑定 ‌:所有属性值或内容需通过 {{}} 绑定动态数据(如 <input value="{{text}}" />),支持简单表达式(如 {{num + 1}})‌。
  • 性能优化 ‌:列表渲染中必须使用 wx:key 提升渲染效率‌。
  • 模板复用 ‌:template 适用于跨页面或组件复用复杂结构‌。

微信小程序的界面跳转

一、基础跳转方式

  1. 声明式导航(<navigator>组件)

    • 基本语法 ‌:通过 url 属性指定目标页面路径,open-type 定义跳转类型‌56。

      html 复制代码
      <!-- 保留当前页面跳转(可返回) -->
      <navigator url="/pages/detail/detail" open-type="navigate">跳转详情页</navigator>
      <!-- 关闭当前页面跳转(不可返回) -->
      <navigator url="/pages/detail/detail" open-type="redirect">重定向跳转</navigator>
    • 参数传递 ‌:通过 URL 查询字符串传递参数,目标页面在 onLoad 中通过 options 接收‌68。

      html 复制代码
      <navigator url="/pages/detail/detail?id=123&name=test">带参跳转</navigator>
  2. 编程式导航(API 调用)

    • 常用 API‌:

      方法 作用 特点
      wx.navigateTo 保留当前页面跳转,可返回 最多支持 10 层页面栈‌
      wx.redirectTo 关闭当前页面跳转,不可返回 页面栈减少一层‌
      wx.switchTab 跳转至 tabBar 页面,关闭其他非 tabBar 页面 仅适用于配置了 tabBar 的页面‌
      wx.reLaunch 关闭所有页面并打开新页面 重置页面栈‌
      wx.navigateBack 返回上一级或多级页面 通过 delta 参数控制返回层级‌
    • 代码示例‌:

      js 复制代码
      // 保留跳转(带参数)
      wx.navigateTo({
        url: '/pages/detail/detail?key=value'
      });
      // 关闭当前页跳转
      wx.redirectTo({
        url: '/pages/home/home'
      });

二、高级跳转场景

  1. 跨小程序跳转

    • 实现方式 ‌:使用 wx.navigateToMiniProgram,需在目标小程序的 app.json 中配置关联‌34。

      js 复制代码
      wx.navigateToMiniProgram({
        appId: '目标小程序AppID',
        path: 'pages/index/index',  // 目标页面路径
        success: () => console.log('跳转成功')
      });
    • 限制‌:需目标小程序开启关联权限,且用户已授权‌。

  2. H5 页面跳转小程序

    • 步骤‌:

      1. 通过第三方平台(如天天外链)生成跳转链接,配置目标小程序路径和参数‌。
      2. 将链接嵌入 H5 页面,用户点击后触发微信内置浏览器跳转逻辑‌。
    • 示例配置‌:

      js 复制代码
      // 生成跳转链接(第三方工具)
      const url = 'https://外链域名/path?appid=小程序ID&path=目标页面';
  3. App 跳转小程序

    • 条件‌:

      • 已认证的开放平台账号可跳转任意合法小程序‌。
      • 未认证账号仅支持跳转同一开放平台下的小程序‌。
    • 实现 ‌:调用微信 SDK 的 WXLaunchMiniProgram 方法‌。


三、常见问题与注意事项

  1. 页面栈管理

    • 使用 getCurrentPages() 获取当前页面栈,避免超过 10 层导致跳转失败‌。
    • reLaunch 会清空页面栈,慎用于高频操作场景‌。
  2. ‌**tabBar 页面限制**‌

    • switchTab 仅支持跳转已在 app.jsontabBar 配置中声明的页面‌。
    • 跳转 tabBar 页面时不可携带参数‌。
  3. 外部跳转兼容性

    • H5 或 App 跳转需确保目标小程序的 app.json 已配置通用链接(Universal Link)‌。
    • 部分安卓机型需手动开启"允许从外部应用跳转"权限‌。

四、最佳实践

  1. 统一路由管理

    • 封装全局路由工具类,集中处理路径拼接、参数编码等逻辑‌。

      js 复制代码
      // utils/router.js
      export const navigateTo = (path, params) => {
        const query = new URLSearchParams(params).toString();
        wx.navigateTo({ url: `${path}?${query}` });
      };
  2. 安全性控制

    • 对跳转参数进行合法性校验,防止注入攻击‌。
    • 跨小程序跳转时校验目标 appId 白名单。
  3. 性能优化

    • 减少 navigateTo 层级,复杂流程优先使用 redirectToreLaunch‌。
    • 预加载目标页面数据,提升跳转后渲染速度‌

微信小程序的生命周期

一、‌应用生命周期

通过 App() 函数注册,在 app.js 中定义,核心函数包括:

  1. onLaunch小程序初始化时触发(仅执行一次),用于获取启动参数或初始化全局数据‌。
  2. onShow小程序启动或从后台进入前台时触发(如用户重新打开小程序)‌。
  3. onHide小程序从前台进入后台时触发(如用户点击右上角关闭)‌。
  4. onError脚本执行错误或 API 调用失败时触发,用于错误监控‌。

二、‌页面生命周期

在页面 .js 文件中定义,通过 Page() 函数注册,关键函数如下:

  1. onLoad页面加载时触发(仅一次),用于获取页面参数或发起网络请求‌。
  2. onShow页面显示/切入前台时触发(如切换回该页面)‌。
  3. onReady页面初次渲染完成时触发(仅一次),用于操作 DOM 或执行交互逻辑‌。
  4. onHide页面隐藏/切入后台时触发(如跳转至其他页面)‌。
  5. onUnload页面销毁时触发(如关闭页面或路由跳转离开),用于清理定时器等资源‌。

三、‌组件生命周期

通过 Component() 函数注册,在组件 .js 中定义,主要函数包括:

  1. created组件实例创建时触发,但尚未挂载到页面节点树‌。
  2. attached组件被添加到页面节点树时触发,可访问页面数据‌。
  3. detached组件从页面节点树移除时触发,用于资源释放‌。
  4. pageLifetimes监听组件所在页面的生命周期(如页面显示/隐藏)‌。

四、‌运行机制与状态切换

  1. 冷启动
    首次打开或销毁后重新启动,触发 onLaunch‌。
  2. 热启动(后台切前台)
    从后台恢复至前台,触发 onShow‌。
  3. 挂起
    后台持续 5 秒无操作后,JS 线程停止,保留内存状态‌。
  4. 销毁
    长时间未使用(30 分钟)或系统资源不足时触发,完全终止运行‌。

生命周期执行顺序示例

text 复制代码
应用启动 → onLaunch → 页面加载 → onLoad → onShow → onReady  
切换后台 → 应用 onHide → 页面 onHide  
重新进入 → 应用 onShow → 页面 onShow  
销毁页面 → 页面 onUnload  

注意事项

  • 性能优化 ‌:避免在 onShow 中频繁执行耗时操作,优先使用 onLoad 初始化数据‌。
  • 数据同步 ‌:页面隐藏时(onHide)保存临时数据,避免丢失‌。
  • 组件复用 ‌:利用 detached 清理组件内事件监听,防止内存泄漏‌。

微信小程序的组件使用

一、组件核心概念
  1. 作用与优势

    • 代码复用‌:封装 UI 和逻辑,避免重复开发。
    • 独立性‌:组件拥有独立的数据、样式和生命周期,与页面解耦。
    • 维护性‌:复杂业务拆分为多个组件,降低代码耦合度。
  2. 组件与页面的区别

    特性 页面 组件
    文件结构 包含 .json 文件声明页面 需在 .json 中声明 "component": true
    生命周期 onLoad, onShow created, attached
    使用方式 通过路由跳转访问 需在页面或父组件中引入

二、组件创建与使用
  1. 创建自定义组件

    • 文件结构‌:

      text 复制代码
      components/
        my-component/
          my-component.js    // 组件逻辑
          my-component.wxml   // 组件模板
          my-component.wxss   // 组件样式
          my-component.json   // 组件配置
    • ‌配置 my-component.json

      json 复制代码
      {
        "component": true,
        "usingComponents": {}  // 可嵌套其他组件
      }
  2. 在页面中引入组件

    • 声明组件 ‌(页面 .json 中):

      json 复制代码
      {
        "usingComponents": {
          "my-component": "/components/my-component/my-component"
        }
      }
    • 使用组件 ‌(页面 .wxml 中):

      html 复制代码
      <my-component prop-a="{{value}}" bind:myevent="handleEvent" />

三、组件核心配置
  1. 数据与属性

    • 内部数据 ‌(data):

      js 复制代码
      Component({
        data: {
          count: 0
        }
      })
    • 外部属性 ‌(properties):支持类型校验和默认值:

      js 复制代码
      Component({
        properties: {
          propA: {
            type: String,
            value: 'default'
          },
          propB: Number // 简写
        }
      })
  2. 事件通信

    • 触发事件‌(子组件向父组件):

      js 复制代码
      // 子组件中触发
      this.triggerEvent('myevent', { detail: data }, { bubbles: false })
    • 监听事件‌(父组件中):

      html 复制代码
      <!-- 父组件.wxml -->
      <my-component bind:myevent="handleEvent" />
  3. 插槽(Slot)

    • 默认插槽‌:

      html 复制代码
      <!-- 组件模板.wxml -->
      <view class="container">
        <slot></slot>
      </view>
      
      <!-- 使用组件 -->
      <my-component>
        <text>插入的内容</text>
      </my-component>
    • 具名插槽‌:

      html 复制代码
      <!-- 组件模板.wxml -->
      <slot name="header"></slot>
      <slot name="footer"></slot>
      
      <!-- 使用组件 -->
      <my-component>
        <text slot="header">头部内容</text>
        <text slot="footer">底部内容</text>
      </my-component>

四、高级功能
  1. 组件间关系

    • 定义关系 ‌(relations):

      js 复制代码
      Component({
        relations: {
          './child-component': {
            type: 'child',
            linked(target) {
              console.log('子组件已链接', target)
            }
          }
        }
      })
    • 访问关联组件 ‌:通过 this.getRelationNodes('./child-component')

  2. 外部样式类

    • 暴露样式类 ‌(组件 .js 中):

      js 复制代码
      Component({
        externalClasses: ['custom-class'] // 允许外部传入样式类
      })
    • 使用外部样式‌(父组件中):

      html 复制代码
      <my-component custom-class="my-style" />
  3. 生命周期

    生命周期 触发时机
    created 组件实例刚创建(不能调用 setData
    attached 组件完全初始化并插入页面 DOM 树
    detached 组件从页面 DOM 树移除

五、常见问题与解决
问题场景 解决方案
组件样式不生效 检查组件 .json 是否声明 "styleIsolation": "apply-shared"(启用样式隔离)
父组件无法监听子组件事件 确认 triggerEvent 的第三个参数未设置 bubbles: false(默认向上冒泡)
插槽内容渲染异常 确保组件 .wxml 中正确使用 <slot name="xxx"> 并与使用端 slot 属性匹配
组件间数据不同步 使用 observers 监听属性变化:properties: { propA: { observer: function } }

六、最佳实践
  1. 性能优化

    • 避免在 attached 生命周期中执行耗时操作。

    • 使用 pureDataPattern 标记纯数据字段,减少不必要的渲染:

      js 复制代码
      Component({
        options: {
          pureDataPattern: /^_/ // 以 _ 开头的字段为纯数据
        },
        data: {
          _internalData: '不参与渲染'
        }
      })
  2. 组件复用性设计

    • 通过 behaviors 复用代码逻辑:

      js 复制代码
      // behavior.js
      module.exports = Behavior({
        methods: {
          sharedMethod() { /* ... */ }
        }
      })
      
      // 组件中引入
      Component({
        behaviors: [require('./behavior.js')]
      })

微信小程序的传值

一、页面间传值

1. ‌URL 参数传递
  • 适用场景‌:页面跳转时传递简单参数(如 ID)。

  • 实现方式‌:

    js 复制代码
    // 跳转时传参(发送方)
    wx.navigateTo({
      url: '/pages/detail/detail?id=123&name=test'
    })
    
    // 接收参数(接收方 detail 页面的 onLoad 函数)
    onLoad(options) {
      const { id, name } = options // id='123', name='test'
    }
  • 注意 ‌:参数需拼接为字符串,复杂数据需用 JSON.stringify 序列化。

2. ‌本地存储
  • 适用场景‌:跨页面持久化数据(如用户 Token)。

  • 实现方式‌:

    js 复制代码
    // 存储数据
    wx.setStorageSync('key', { a: 1 })
    
    // 读取数据(任意页面)
    const data = wx.getStorageSync('key')
  • 注意 ‌:避免存储过大或敏感数据,异步 API 可用 wx.setStorage


二、组件间传值

1. ‌父传子:Properties
  • 适用场景‌:父组件向子组件传递静态或动态数据。

  • 实现方式‌:

    html 复制代码
    <!-- 父组件使用子组件 -->
    <child-component prop-a="{{value}}" />
    
    <!-- 子组件定义 properties -->
    Component({
      properties: {
        propA: {
          type: String,
          value: '默认值'
        }
      }
    })
2. ‌子传父:自定义事件
  • 适用场景‌:子组件向父组件传递数据或触发行为。

  • 实现方式‌:

    js 复制代码
    // 子组件触发事件
    this.triggerEvent('eventName', { data: 123 })
    
    // 父组件监听事件
    <child-component bind:eventName="handleEvent" />
    
    // 父事件处理函数
    handleEvent(e) {
      const data = e.detail.data // 123
    }
3. ‌兄弟组件传值
  • 方法一‌:通过父组件中转(结合 Properties + 事件)。
  • 方法二‌:使用全局事件总线(需自行封装或使用库)。

三、全局数据管理

1. ‌全局变量(app.js)
  • 适用场景‌:多页面共享数据(如用户信息)。

  • 实现方式‌:

    js 复制代码
    // app.js 中定义
    App({
      globalData: {
        token: 'xxxx'
      }
    })
    
    // 任意页面或组件获取
    const app = getApp()
    console.log(app.globalData.token)
2. ‌状态管理工具
  • 推荐库 ‌:wechat-weapp-reduxmobx-miniprogram
  • 适用场景‌:复杂应用的多组件状态同步。

四、其他传值方式

1. ‌页面栈传值
  • 适用场景‌:返回上一页时传递数据。

  • 实现方式‌:

    js 复制代码
    // 获取页面栈实例
    const pages = getCurrentPages()
    const prevPage = pages[pages.length - 2] // 上一页实例
    
    // 修改上一页数据
    prevPage.setData({ backData: '123' })
    
    // 返回上一页
    wx.navigateBack()
2. ‌通过 Dataset 传递
  • 适用场景‌:事件触发时传递元素自定义数据。

  • 实现方式‌:

    html 复制代码
    <view data-id="123" bindtap="handleTap"></view>
    
    <script>
      handleTap(e) {
        const id = e.currentTarget.dataset.id // '123'
      }
    </script>

五、最佳实践总结

场景 推荐方法 注意事项
简单页面跳转传参 URL 参数 数据量小,避免复杂结构
父子组件通信 Properties + 自定义事件 避免滥用双向绑定
跨页面持久化数据 本地存储(wx.setStorageSync 定期清理过期数据
全局共享状态 app.globalData 或状态管理库 复杂项目优先使用 Redux/MobX
兄弟组件通信 父组件中转或全局事件 结构复杂时考虑状态管理工具

关键注意事项

  1. 性能优化‌:避免频繁传递大数据,优先通过 ID 查询详情。
  2. 数据安全‌:敏感数据(如密码)禁止明文存储或传递。
  3. 内存管理 ‌:页面销毁时(onUnload)及时清理无用数据。

微信登录流程

一、流程图解
sequenceDiagram participant 用户 participant 小程序前端 participant 开发者服务器 participant 微信服务器 用户->>小程序前端: 触发登录操作 小程序前端->>微信服务器: 调用 wx.login() 获取 code ‌:ml-citation{ref="1,6" data="citationList"} 微信服务器-->>小程序前端: 返回临时登录凭证 code 小程序前端->>开发者服务器: 发送 code ‌:ml-citation{ref="1,2" data="citationList"} 开发者服务器->>微信服务器: 用 code 换取 session_key 和 openid ‌:ml-citation{ref="2,6" data="citationList"} 微信服务器-->>开发者服务器: 返回 session_key 和 openid 开发者服务器->>开发者服务器: 生成自定义登录态(如 Token) 开发者服务器-->>小程序前端: 返回 Token 和用户信息(可选) 小程序前端->>小程序前端: 存储 Token 至本地缓存 ‌:ml-citation{ref="1,6" data="citationList"}

二、分步流程说明
  1. 用户触发登录操作

    用户点击登录按钮,小程序前端调用 wx.login() 接口获取临时登录凭证 code,有效期 5 分钟‌。

  2. 发送 code 至开发者服务器

    小程序通过 HTTPS 请求将 code 发送至开发者服务器,用于换取用户唯一标识 openid 和会话密钥 session_key‌。

  3. 换取 session_key 和 openid

    开发者服务器调用微信接口 https://api.weixin.qq.com/sns/jscode2session,提交以下参数:

    • appid:小程序 ID
    • secret:小程序密钥
    • js_code:接收到的 code
    • grant_type:固定为 authorization_code
      微信服务器返回 openid(用户唯一标识)和 session_key(会话密钥)‌。
  4. 生成自定义登录态

    开发者服务器根据业务需求生成自定义登录态(如 JWT Token),并与 openid 绑定存储至数据库或缓存系统‌。

  5. 返回 Token 至小程序

    开发者服务器将 Token 返回给小程序前端,前端通过 wx.setStorageSync 存储至本地缓存,后续请求携带 Token 验证身份‌。


三、关键注意事项
  1. 安全性要求

    • session_key 严禁传输至客户端,仅用于服务端解密用户敏感数据(如手机号)‌。
    • Token 需设置有效期,建议结合 session_key 过期时间(默认 30 分钟)‌。
  2. 用户信息获取

    • 若需获取用户昵称、头像等,需调用 wx.getUserProfile 并引导用户授权‌。
    • 加密数据(如 encryptedData)需在服务端用 session_key 解密‌。
  3. 登录态维护

    • 建议在 app.globalData 或本地缓存中存储 Token,定期检查过期时间并自动续期‌。

四、常见问题处理

| ‌问题‌ | ‌解决方案‌ |
|--------------------|------------------------------|---|
| code 失效(超时/重复使用) | 重新调用 wx.login() 获取新 code | ‌ |
| session_key 泄露风险 | 限制接口调用频率,避免明文传输敏感数据 |
| 多端登录冲突 | 基于 openid 绑定设备标识,强制下线旧设备 |

微信支付流程

一、流程图解

sequenceDiagram participant 用户 participant 小程序前端 participant 开发者服务器(后端) participant 微信支付系统 用户->>小程序前端: 进入小程序,选择商品并下单 小程序前端->>开发者服务器: 发送订单请求(商品信息、金额等)‌:ml-citation{ref="3,5" data="citationList"} 开发者服务器->>微信支付系统: 调用「统一下单接口」生成预付单(含 prepay_id)‌:ml-citation{ref="3,5" data="citationList"} 微信支付系统-->>开发者服务器: 返回 prepay_id 和签名参数‌:ml-citation{ref="3,5" data="citationList"} 开发者服务器-->>小程序前端: 返回支付参数(含 prepay_id 和签名)‌:ml-citation{ref="3,5" data="citationList"} 小程序前端->>微信支付系统: 调用 wx.requestPayment 调起支付控件‌:ml-citation{ref="2,8" data="citationList"} 微信支付系统-->>用户: 弹出支付界面(输入密码/指纹验证)‌:ml-citation{ref="2,8" data="citationList"} 用户->>微信支付系统: 完成支付 微信支付系统-->>开发者服务器: 异步通知支付结果(回调接口)‌:ml-citation{ref="5,8" data="citationList"} 开发者服务器->>开发者服务器: 更新订单状态,处理业务逻辑‌:ml-citation{ref="5" data="citationList"} 开发者服务器-->>小程序前端: 返回支付成功状态‌:ml-citation{ref="5,8" data="citationList"} 小程序前端->>用户: 显示支付成功页面‌:ml-citation{ref="2,8" data="citationList"}

二、分步流程说明

  1. 前置条件

    • 小程序需完成企业认证,并关联微信支付商户号(主体一致)‌
    • 开发者服务器需配置 appidmch_id(商户号)、API 密钥等敏感信息‌
  2. 核心步骤

    ① 用户下单

    • 用户在小程序内选择商品,点击「支付」按钮触发支付流程‌
    • 小程序前端调用 wx.login() 获取 code,发送至后端换取用户 openid(用户唯一标识)‌

    ② 生成预付单

    • 开发者服务器调用微信支付「统一下单接口」,提交以下参数:

      • openid(用户标识)
      • body(商品描述)
      • total_fee(金额,单位为分)
      • notify_url(支付结果回调地址)‌
    • 微信支付返回 prepay_id(预付单标识)和签名参数(paySignnonceStr 等)‌

    ③ 调起支付控件

    • 小程序前端通过 wx.requestPayment 调起支付界面,携带以下参数:

      • timeStamp(时间戳)
      • nonceStr(随机字符串)
      • package(格式:prepay_id=xxx
      • signType(签名类型,默认 MD5HMAC-SHA256
      • paySign(服务端生成的签名)‌

    ④ 支付结果处理

    • 支付成功:微信支付异步通知开发者服务器(需验证签名和金额一致性)‌
    • 支付失败:前端显示错误提示(如余额不足、网络异常等)‌

三、前端代码案例

用户触发支付按钮
js 复制代码
// pages/pay/pay.js
Page({
  handlePayment() {
    // 1. 获取用户openid(需提前登录)
    const openid = wx.getStorageSync('openid');

    // 2. 向后端请求支付参数
    wx.request({
      url: 'https://your-api.com/create-pay-order',
      method: 'POST',
      data: {
        productId: '123',   // 商品ID
        totalFee: 100,      // 金额(单位:分)
        openid: openid      // 用户唯一标识
      },
      success: (res) => {
        // 3. 接收后端返回的支付参数
        const payParams = res.data;
        this.launchPayment(payParams);
      },
      fail: (err) => {
        wx.showToast({ title: '订单创建失败', icon: 'none' });
      }
    });
  },

  // 调起微信支付
  launchPayment(payParams) {
    wx.requestPayment({
      timeStamp: payParams.timeStamp,  // 时间戳(秒级)
      nonceStr: payParams.nonceStr,    // 随机字符串
      package: payParams.package,      // prepay_id=xxx
      signType: 'RSA',                 // 2025年起强制使用RSA签名
      paySign: payParams.paySign,       // 服务端生成的签名
      success: (res) => {
        // 4. 支付成功处理
        wx.showToast({ title: '支付成功' });
        this.checkOrderStatus();
      },
      fail: (err) => {
        // 5. 支付失败处理
        const errMsg = err.errMsg || '支付中断';
        wx.showToast({ title: errMsg, icon: 'none' });
      }
    });
  },

  // 查询最终订单状态(兜底逻辑)
  checkOrderStatus() {
    wx.request({
      url: 'https://your-api.com/check-order',
      method: 'POST',
      data: { orderId: 'ORDER_123' },
      success: (res) => {
        if (res.data.status === 'SUCCESS') {
          wx.navigateTo({ url: '/pages/success/success' });
        }
      }
    });
  }
});

四、核心代码说明

1. 支付参数获取
参数 来源 示例值
timeStamp 服务端生成(秒级时间戳) "1717027890"
nonceStr 服务端生成的随机字符串 "a1b2c3d4e5f6g7h8"
package 微信返回的预付单标识 "prepay_id=wx1234567890"
signType 固定为 RSA(2025 年强制要求) "RSA"
paySign 服务端使用商户私钥生成的 RSA 签名 "MIIEvQIBADANBg..."
2. 安全校验要点
js 复制代码
// 支付参数校验示例(前端辅助验证)
function validateParams(payParams) {
  const requiredFields = ['timeStamp', 'nonceStr', 'package', 'paySign'];
  return requiredFields.every(field => payParams[field]);
}

// 调用支付前验证参数
if (!validateParams(payParams)) {
  wx.showToast({ title: '支付参数异常', icon: 'none' });
  return;
}

五、支付流程注意事项

  1. 签名安全

    • 服务端必须使用 ‌微信商户平台 ‌ 的 API 私钥生成 paySign
    • 禁止在前端生成签名或传输私钥
  2. 支付结果兜底

    • 即使收到支付成功回调,仍需通过 checkOrderStatus 查询最终状态
    • 处理场景:网络中断、用户关闭小程序等异常
  3. 用户体验优化

    js 复制代码
    // 支付超时处理(30秒限制)
    setTimeout(() => {
      wx.showToast({ title: '支付超时,请重试', icon: 'none' });
    }, 30000);
  4. 错误码处理

    js 复制代码
    // 常见错误码处理
    const errorMap = {
      'requestPayment:fail cancel': '用户取消支付',
      'requestPayment:fail no auth': '未授权支付功能'
    };
    
    wx.requestPayment({
      // ...
      fail: (err) => {
        const message = errorMap[err.errMsg] || '支付失败';
        wx.showToast({ title: message, icon: 'none' });
      }
    });

六、测试建议

  1. 沙箱环境

    js 复制代码
    // 测试环境开关
    const isTestEnv = true; // 上线前设为false
    const API_BASE_URL = isTestEnv 
      ? 'https://test.your-api.com' 
      : 'https://prod.your-api.com';

微信小程序分包

一、分包背景与目的
  1. 核心限制

    • 整个小程序所有分包大小不超过30M(服务商代开发的小程序不超过20M
    • 单个分包/主包大小不能超过2M
    • 独立分包可独立运行,无需依赖主包加载‌
  2. 主要优势

    • 优化首次启动速度,仅下载主包‌36
    • 支持多团队协作开发,按功能模块拆分代码‌27
    • 突破主包体积限制,扩展小程序功能‌16

二、分包项目构成
  1. 目录结构示例
text 复制代码
├── app.js              # 主包入口文件
├── app.json            # 分包配置(含 subpackages 字段)
├── pages/              # 主包页面(含 TabBar 页面)
│   ├── index
│   └── profile
├── subPackage1/        # 分包1
│   └── pages/
│       ├── cart
│       └── detail
└── subPackage2/        # 分包2
    └── pages/
        ├── order
        └── payment
  • 主包 ‌:必须包含启动页(如 pages/index)和 TabBar 页面‌
  • 分包‌:独立目录存放页面、组件及私有资源‌
  1. ‌配置文件 app.json
json 复制代码
{
  "pages": ["pages/index", "pages/profile"],
  "subpackages": [
    {
      "root": "subPackage1",    // 分包根目录
      "name": "shopModule",     // 分包别名(可选)
      "pages": ["pages/cart", "pages/detail"], 
      "independent": false      // 是否独立分包
    },
    {
      "root": "subPackage2",
      "pages": ["pages/order", "pages/payment"]
    }
  ]
}
  • root:分包根目录路径‌
  • independent:设置为 true 时,分包可独立运行‌

三、分包加载规则与限制
  1. 加载规则

    • 启动小程序时仅下载主包,访问分包页面时动态加载对应子包‌
    • 独立分包首次访问时直接加载,无需主包依赖‌
  2. 体积限制

    类型 大小限制 说明
    主包 ≤ 2MB 含公共资源和 TabBar 页面‌
    单个分包 ≤ 2MB 独立分包也需遵守‌
    所有分包总和 整个小程序所有分包大小不超过 30M(服务商代开发的小程序不超过 20M)
  3. 预加载分包

    • 通过 preloadRule 配置提前加载高频使用的分包‌
json 复制代码
{
  "preloadRule": {
    "pages/index": {
      "network": "all",
      "packages": ["subPackage1"]  // 访问主包 index 页时预加载分包1
    }
  }
}

四、分包开发注意事项
  1. 路径配置

    • 分包内页面路径需相对于 root 目录(如 subPackage1/pages/cart)‌
    • 跨分包跳转需使用绝对路径:/subPackage1/pages/cart
  2. 资源引用

    • 分包私有资源(如图片、样式)需存放于分包目录内‌
    • 公共资源建议放置在主包,避免重复打包‌
  3. 常见错误

    • TabBar 页面放在分包中‌:必须保留在主包‌
    • 分包路径配置错误‌:导致页面无法加载或白屏‌

五、优化策略
  1. 公共资源提取

    • 将通用组件、工具库(如 utils)放置在主包‌
    • 使用 npmVant 等第三方库时,优先选择按需加载‌
  2. 独立分包使用场景

    • 营销活动页、支付流程等高频独立功能‌
    • 示例:独立分包中配置 "independent": true 实现快速启动‌
  3. 分包大小监控

    • 通过开发者工具「代码依赖分析」检测分包体积‌
    • 超限解决方案:压缩图片、删除冗余代码、拆分更小子包‌

微信小程序 npm 构建详解(以 Vant Weapp 为例)

一、构建流程

  1. 初始化 npm 项目

    bash 复制代码
    cd /your-project-path  # 进入项目根目录
    npm init -y            # 自动生成 package.json ‌:ml-citation{ref="4,6" data="citationList"}
    • 云开发项目需进入 miniprogram 子目录执行初始化‌。
  2. 安装 Vant Weapp

    bash 复制代码
    npm i @vant/weapp -S --production
  3. 配置文件调整

    • ‌删除 app.json 中的 "style": "v2" ‌:避免基础组件样式冲突‌。

    • ‌修改 project.config.json

      json 复制代码
      {
        "setting": {
          "packNpmManually": true,
          "packNpmRelationList": [{
            "packageJsonPath": "./package.json",
            "miniprogramNpmDistDir": "./miniprogram/"  # 指向项目根目录 ‌:ml-citation{ref="1,4" data="citationList"}
          }]
        }
      }
  4. 构建 npm

    • 微信开发者工具中点击 ‌工具 > 构建 npm ‌,成功生成 miniprogram_npm 目录‌。

二、Vant Weapp 集成

  1. 引入组件

    • 全局配置(app.json ‌:

      json 复制代码
      {
        "usingComponents": {
          "van-button": "@vant/weapp/button/index"  # 路径包含 miniprogram_npm ‌:ml-citation{ref="2,5" data="citationList"}
        }
      }
    • 页面级配置(页面 .json 文件) ‌:按需引入减少体积‌57。

  2. 全局样式加载

    css 复制代码
    /* app.wxss */
    @import '/miniprogram_npm/@vant/weapp/common/index.wxss';  # 引入 Vant 基础样式 ‌:ml-citation{ref="1,6" data="citationList"}
  3. 组件使用示例

    html 复制代码
    <!-- 页面.wxml -->
    <van-button type="primary" bind:click="handleClick">提交</van-button>

三、常见问题与解决
问题 解决方案
构建后无 miniprogram_npm 目录 检查 project.config.jsonminiprogramNpmDistDir 路径是否匹配项目结构‌
npm install 报错权限不足** 以管理员身份运行开发者工具,或手动创建 package.json 后重试‌
组件样式不生效 确认已删除 app.json"style": "v2" 并正确引入全局样式文件‌
‌**提示 Component not found**‌ 检查组件路径是否为 @vant/weapp/xxx/index(构建后自动映射到 miniprogram_npm)‌

四、最佳实践
  1. 版本控制

    • 固定依赖版本(如 @vant/weapp@2.15.0),避免自动升级导致兼容性问题‌。
    • 定期执行 npm outdated 检测更新‌。
  2. 分包优化

    • 主包存放公共组件,独立分包单独声明依赖(需在分包目录创建 package.json)‌。
  3. 性能监控

    • 使用开发者工具 ‌代码体积分析‌ 功能,对超过 2MB 的分包进行代码拆分或压缩‌。

其他可参考

developers.weixin.qq.com/miniprogram...

相关推荐
zoahxmy092910 小时前
微信小程序 request 流式数据处理
微信小程序
人人题11 小时前
汽车加气站操作工考试答题模板
笔记·职场和发展·微信小程序·汽车·创业创新·学习方法·业界资讯
曲江涛13 小时前
微信小程序 webview 定位 并返回
微信小程序·小程序
weixin_4404705013 小时前
部署Dify接入微信验证反代根目录创建一个文件通过微信小程序验证
微信小程序·腾讯云
web_Hsir14 小时前
uniapp 微信小程序 使用ucharts
微信小程序·小程序·uni-app
web_Hsir14 小时前
Uniapp 实现微信小程序滑动面板功能详解
vue.js·微信小程序·uni-app
Angus-zoe16 小时前
微信小程序唤起app
微信小程序·小程序
不老刘17 小时前
微信小程序使用 Vant Weapp 组件库教程
微信小程序·小程序·vant
橘猫云计算机设计17 小时前
基于springboot微信小程序的旅游攻略系统(源码+lw+部署文档+讲解),源码可白嫖!
java·spring boot·后端·微信小程序·毕业设计·旅游
Mr.Liu618 小时前
小程序30-wxml语法-声明和绑定数据
前端·微信小程序·小程序