小程序

258 阅读14分钟

小程序讲解

作为前端程序员,你已经掌握了 HTML、CSS、JavaScript 等核心技能,学习小程序开发会非常容易上手 —— 因为小程序的开发思想和前端高度一致,只是在语法规范、API 生态和工具链上有平台特定的规则。以下从 核心语法、开发流程、技术栈、进阶技巧 四个维度,为你详细讲解小程序开发知识:

一、小程序与前端开发的核心差异(先搞懂 “不一样” 的地方)

  1. 语法规范

    • 前端用 HTML 写结构,小程序用平台自定义标签(如微信用 WXML,支付宝用 AXML),标签名更语义化(如 <view> 对应 <div><text> 对应 <span><image> 对应 <img>)。
    • 前端用 CSS 写样式,小程序用平台样式表(如微信 WXSS、支付宝 ACSS),支持大部分 CSS 语法,但新增了 rpx 单位(自适应屏幕,1rpx = 屏幕宽度 / 750,解决多设备适配问题)。
    • 逻辑层仍用 JavaScript,但小程序对 ES6+ 语法的支持需看平台版本(通常支持 async/await、箭头函数,但部分老版本不支持 import 需用 require)。
  2. 运行环境

    • 前端运行在浏览器中,受浏览器安全策略限制(如跨域需后端配置 CORS);
    • 小程序运行在平台的 沙箱环境 中(如微信的 X5 内核),有独立的 API 体系(如调用摄像头、支付需用平台提供的 API),跨域请求需在平台后台配置 “合法域名”
  3. 生命周期

    • 前端页面生命周期由浏览器控制(loadDOMContentLoaded 等);
    • 小程序有 应用生命周期(如微信的 onLaunch 初始化、onShow 切入前台)和 页面生命周期(如 onLoad 页面加载、onReady 初次渲染完成),需在对应钩子中处理逻辑。

二、核心开发知识(以微信小程序为例,其他平台大同小异)

1. 项目结构(约定式开发,类似 Vue 的单文件组件)
├── app.js          // 应用入口,定义应用生命周期
├── app.json        // 全局配置(页面路径、窗口表现、导航栏等)
├── app.wxss        // 全局样式
├── pages/          // 页面目录(每个页面一个子目录)
│   ├── index/      // 首页
│   │   ├── index.js   // 页面逻辑(数据、生命周期、方法)
│   │   ├── index.wxml // 页面结构
│   │   ├── index.wxss // 页面样式
│   │   └── index.json // 页面配置(覆盖全局配置)
├── components/     // 自定义组件目录
├── utils/          // 工具函数
└── project.config.json // 项目配置(如 appid、编译配置)
2. 数据绑定与渲染(类似 Vue 的双向绑定思想)
  • 数据定义:在页面的 data 对象中声明数据(如 { count: 0, list: [] })。

  • 模板渲染

    • 文本绑定:{{ count }}(类似 Vue 的 {{ }});
    • 条件渲染:<view wx:if="{{ isShow }}">显示</view>(替代 v-if);
    • 列表渲染:<view wx:for="{{ list }}" wx:key="index">{{ item }}</view>(替代 v-for)。
  • 事件处理:通过 bind:tap 绑定点击事件(如 <button bind:tap="handleClick">点击</button>),在 index.js 中定义 handleClick(e) { ... },通过 this.setData({ count: 1 }) 更新数据(类似 React 的 setState,异步更新 DOM)。

3. 路由与导航(平台内置,无需引入路由库)
  • 全局路由配置:在 app.json 的 pages 数组中声明页面路径(第一个为首页)

    { "pages": ["pages/index/index", "pages/detail/detail"] }
    
  • 导航方式:

    • 标签导航:<navigator url="/pages/detail/detail">跳转到详情</navigator>
    • 编程式导航:wx.navigateTo({ url: '/pages/detail/detail' })(保留当前页,类似 push);
    • 返回上一页:wx.navigateBack()(类似 pop)。
4. 网络请求(平台封装,需配置合法域名
  • 用 wx.request 发起请求(替代 fetch 或 axios

    wx.request({
      url: 'https://api.example.com/data', // 需在微信公众平台配置为合法域名
      method: 'GET',
      success: (res) => { console.log(res.data) },
      fail: (err) => { console.error(err) }
    });
    
  • 注意:本地开发可勾选 “不校验合法域名”,上线前必须配置。

5. 自定义组件(复用 UI 和逻辑,类似 Vue 组件)
  • 定义组件:在 components/ 目录下创建组件(如 my-button),结构与页面一致(my-button.jsmy-button.wxml 等)。

  • 注册组件:在页面的 index.json 中声明:

    { "usingComponents": { "my-button": "/components/my-button/my-button" } }
    
  • 使用组件:在 index.wxml 中直接引用 <my-button text="点击" bind:click="onBtnClick" />,通过 properties 接收参数,triggerEvent 触发自定义事件。

三、开发工具与流程(以微信小程序为例)

  1. 工具准备

    • 下载 微信开发者工具(集成编辑器、模拟器、调试器)。
    • 注册微信公众平台账号,获取 appid(测试可先用 “测试号”)。
  2. 开发流程

    • 新 建项目:选择小程序项目,输入 appid(或测试号),选择目录。
    • 编写代码:在编辑器中写 wxmlwxssjs,实时在模拟器预览。
    • 调试:用 “调试器” 查看 console、network、DOM 结构(类似 Chrome DevTools)。
    • 预览:通过工具生成二维码,用手机微信扫码查看真实效果。
    • 发布:上传代码到微信公众平台,审核通过后发布上线

四、前端程序员的进阶技巧(复用你的前端经验)

  1. 样式复用

    • 用 @import 导入公共样式(如 @import "/styles/common.wxss";)。
    • 利用 less/sass 编写样式:在开发者工具中开启 “使用 npm 模块”,通过 gulp 或 webpack 将 less 编译为 wxss(类似前端工程化)。
  2. 状态管理

    • 简单场景:用 getApp() 获取全局 App 实例,在 app.js 中定义全局数据(如用户信息)。
    • 复杂场景:引入前端常用的状态管理库(如 mobx-miniprogram 或简化版 redux),管理跨页面数据。
  3. 跨平台开发(一次开发多端运行)

    • 如果你需要同时开发微信、支付宝、抖音小程序,可使用 Taro 或 UniApp(基于 React/Vue 语法,编译到多端),复用你已有的 React/Vue 技能。
  4. 性能优化(小程序特有)

    • 减少 setData 调用:setData 会触发页面重渲染,避免频繁调用,可合并数据后一次性更新。
    • 图片优化:用 image 组件的 lazy-load 懒加载,通过 wx.getImageInfo 预加载大图。
    • 分包加载:将大项目拆分为 “主包 + 分包”,用户进入对应页面才下载分包,减少首次启动时间。

五、其他平台小程序的差异(快速迁移)

  • 支付宝小程序:语法类似微信,但标签名和 API 有差异(如 a:if 替代 wx:ifmy.request 替代 wx.request),侧重支付和生活服务场景。
  • 抖音 / 头条小程序:基于字节跳动生态,支持短视频挂载,API 前缀为 tt.(如 tt.request)。
  • 统一规律:所有平台的小程序都遵循 “结构 - 样式 - 逻辑” 分离的思想,核心差异在 API 前缀和平台特有功能(如微信的社交分享、支付宝的芝麻信用),熟悉一个平台后,迁移到其他平台只需适配 API 即可。

作为前端开发者,你可以把小程序看作 “前端技术的子集 + 平台特定 API”,重点掌握 数据绑定、生命周期、组件化、平台 API 这四点,就能快速上手开发。如果需要具体场景的实战示例(如登录功能、支付集成),可以进一步提问!

高频面试题

小程序开发作为前端领域的重要分支,面试中常围绕基础语法、框架特性、性能优化、实战场景等展开。以下是高频面试题及详细解析,结合前端开发者的知识体系帮你快速掌握核心考点:

一、基础概念与语法

  1. 小程序与普通网页(H5)的区别?

    • 运行环境:小程序 运行在平台自研的沙箱环境(如微信的 X5 内核),H5 运行在浏览器中;

    • 权限:小程序可调用平台原生能力(如摄像头、支付、地理位置),H5 受浏览器安全限制,权限较少;

    • 更新机制:小程序需提交审核发布,H5 可实时更新。

    • 资源加载:小程序有体积限制(通常 2MB 内,分包可扩展),加载更快;H5 依赖网络加载,受网速影响大;

    • 路由管理:小程序内置路由(wx.navigateTo 等),H5 需手动实现或用 vue-router 等库;

  2. 小程序的目录结构有哪些核心文件?各自作用是什么?

    • 全局文件:

      • app.js:应用入口,定义应用生命周期(onLaunchonShowonHide)和全局数据;
      • app.json:全局配置(页面路径、窗口样式、导航栏、tabBar 等);
      • app.wxss:全局样式,作用于所有页面。
    • 页面文件(每个页面一个目录):

      • page.js:页面逻辑(数据、生命周期、事件方法);
      • page.wxml:页面结构(类似 HTML,用自定义标签如 <view><text>);
      • page.wxss:页面样式(支持 rpx 单位,优先级高于全局样式);
      • page.json:页面配置(覆盖全局配置,如单独设置导航栏标题)。
  3. 小程序的生命周期有哪些?应用生命周期和页面生命周期的区别?

    • 应用生命周期app.js 中定义):

      • onLaunch小程序初始化完成(全局只触发一次)
      • onShow:小程序切入前台时触发(如从后台切换回来);
      • onHide:小程序切入后台时触发(如按手机 Home 键)。
    • 页面生命周期page.js 中定义):

      • onLoad页面加载时触发(接收路由参数,只触发一次)
      • onShow:页面显示时触发(每次切换到该页面都会触发);
      • onReady:页面初次渲染完成(可操作 DOM,只触发一次);
      • onHide:页面隐藏时触发(如跳转到其他页面);
      • onUnload页面卸载时触发(如返回上一页并关闭当前页)
    • 区别:应用生命周期贯穿小程序全局,页面生命周期只针对单个页面的创建到销毁。

二、核心特性与 API

  1. 小程序的数据绑定原理?setData 有什么注意事项?

    • 原理:类似 Vue 的单向数据绑定,通过 {{ }} 在 WXML 中绑定 data 中的数据,当 data 变化时,视图自动更新。

    • setData 注意事项:

      • 必须用 this.setData({ key: value }) 更新数据,直接修改 this.data 不会触发视图更新
      • 是异步操作,修改后不能立即获取更新后的数据(可在回调中处理:this.setData({ ... }, () => { ... }));
      • 避免频繁调用(会触发页面重渲染),建议合并数据后一次性更新
      • 支持路径形式修改对象 / 数组(如 this.setData({ 'user.name': 'xxx' }))。
  2. 小程序的路由跳转方式有哪些?区别是什么?

    • 主要方式:

      • wx.navigateTo({ url: 'xxx' }):保留当前页面,跳转到新页面(栈深最多 10 层);
      • wx.redirectTo({ url: 'xxx' }):关闭当前页面,跳转到新页面(替换当前栈);
      • wx.navigateBack({ delta: 1 }):返回上一页面(delta 为返回层数);
      • wx.switchTab({ url: 'xxx' }):跳转到 tabBar 页面,关闭其他所有非 tabBar 页面;
      • wx.reLaunch({ url: 'xxx' }):关闭所有页面,跳转到新页面。
    • 区别:核心在是否保留当前页面、是否受 tabBar 限制、栈管理机制不同。

  3. 小程序如何发起网络请求?有哪些限制?

    • 用 wx.request 发起请求(类似 axios):

      wx.request({
        url: 'https://api.example.com/data',
        method: 'GET',
        data: { id: 1 },
        success: (res) => console.log(res.data),
        fail: (err) => console.error(err)
      })
      
    • 限制:

      • 只能请求 https 接口(本地开发可关闭校验)
      • 需在平台后台配置 “合法域名”(不支持 IP 地址)
      • 并发数限制(通常 10 个)
      • 超时时间默认 60 秒,可通过 timeout 配置。
  4. 小程序的 wx:if 和 hidden 的区别?如何选择?

    • wx:if:动态创建 / 销毁元素,条件为 false 时不渲染该节点(惰性渲染);

    • hidden通过 display: none 隐藏元素,节点始终存在于 DOM 中

    • 选择:

      • 频繁切换显示 / 隐藏时用 hidden(避免频繁创建 / 销毁节点,性能更好);
      • 条件很少变化时用 wx:if(减少初始渲染的节点数)。

三、组件化开发

  1. 小程序如何自定义组件?组件间如何通信?

    • 自定义组件步骤

      1. 创建组件目录(如 components/my-btn),包含 my-btn.jsmy-btn.wxmlmy-btn.wxssmy-btn.json
      2. 在组件 json 中声明 { "component": true }
      3. 在使用组件的页面 json 中注册:{ "usingComponents": { "my-btn": "/components/my-btn/my-btn" } }
      4. 在页面 wxml 中使用:<my-btn />
    • 组件通信方式

      • 父传子:通过 properties 定义属性(如 properties: { text: { type: String, value: '默认值' } }),父组件用 <my-btn text="按钮" /> 传递;
      • 子传父:子组件通过 this.triggerEvent('eventName', data) 触发事件,父组件用 bind:eventName 接收(如 <my-btn bind:click="onBtnClick" />);
      • 全局通信:用 getApp() 获取全局实例,通过全局数据共享;或用 wx.setStorageSync 存储数据(适合简单场景)
  2. 小程序的 slot 插槽用法?如何实现具名插槽和作用域插槽?

    • 默认插槽:组件中用 <slot /> 占位,父组件在使用时传入内容:

      <!-- 组件 wxml -->
      <view><slot /></view>
      <!-- 父组件使用 -->
      <my-btn><text>按钮内容</text></my-btn>
      
    • 具名插槽:组件中用 <slot name="left" /> 定义,父组件用 slot="left" 指定内容:

      <!-- 组件 wxml -->
      <view>
        <slot name="left" />
        <slot name="right" />
      </view>
      <!-- 父组件使用 -->
      <my-btn>
        <text slot="left"></text>
        <text slot="right"></text>
      </my-btn>
      
    • 作用域插槽(传递组件数据给父组件):组件用 slot-scope 暴露数据,父组件接收:

      <!-- 组件 wxml -->
      <view>
        <slot data="{{ item }}" />
      </view>
      <!-- 父组件使用 -->
      <my-list>
        <view slot-scope="scope">{{ scope.item.name }}</view>
      </my-list>
      

四、性能优化

  1. 小程序的性能优化方法有哪些?

    • 启动优化

      • 减小主包体积(主包控制在 2MB 内),用分包加载(subPackages 配置,进入分包页面才下载);
      • 预加载关键资源(preloadRule 配置分包预加载)。
    • 渲染优化

      • 减少 setData 调用频率(合并数据更新);
      • setData 只传需要修改的字段(避免传递整个大对象);
      • 列表渲染用 wx:key(提高重排效率),避免渲染大量数据(可分页加载)。
    • 资源优化

      • 图片压缩(用 image 组件的 mode 裁剪,避免大图缩放);
      • 图片懒加载(lazy-load: true);
      • 复用 wx.createCanvasContext 等实例,避免频繁创建。
    • 代码优化

      • 移除未使用的代码和资源;
      • 用 function 声明方法(箭头函数可能导致 this 指向问题);
      • 避免在 onShow 中做 heavy 操作(影响页面切换流畅度)。
  2. 小程序的分包加载原理?如何配置?

    • 原理:将小程序拆分为 “主包” 和 “分包”,主包包含启动页和公共资源,分包包含其他页面。用户首次启动只下载主包,进入分包页面时才下载对应分包,减少首次启动时间。

    • 配置(app.json):

      {
        "pages": ["pages/index/index"], // 主包页面
        "subPackages": [
          {
            "root": "pages/detail", // 分包根目录
            "pages": ["index/index"] // 分包内页面
          }
        ],
        "preloadRule": { // 预加载配置(进入首页时预加载详情分包)
          "pages/index/index": {
            "network": "all",
            "packages": ["pages/detail"]
          }
        }
      }
      

五、实战场景与问题解决

  1. 小程序如何实现登录功能?

    • 流程(以微信小程序为例):

      1. 调用 wx.login() 获取临时登录凭证 code
      2. 将 code 发送到后端,后端通过微信接口(https://api.weixin.qq.com/sns/jscode2session)换取 openid(用户唯一标识)和 session_key
      3. 后端生成自定义登录态(如 token),返回给小程序;
      4. 小程序存储 tokenwx.setStorageSync('token', token)),后续请求携带 token 验证身份。
    • 代码示例:

      // 小程序端
      wx.login({
        success: (res) => {
          if (res.code) {
            wx.request({
              url: 'https://api.example.com/login',
              data: { code: res.code },
              success: (res) => {
                wx.setStorageSync('token', res.data.token);
              }
            });
          }
        }
      });
      
  2. 小程序如何处理本地存储?有哪些限制?

    • 用 wx.setStorageSync(同步)或 wx.setStorage(异步)存储数据:

      wx.setStorageSync('userInfo', { name: '张三' }); // 存储
      const userInfo = wx.getStorageSync('userInfo'); // 读取
      wx.removeStorageSync('userInfo'); // 删除
      
    • 限制:

      • 单个 key 最大 1MB,总存储上限约 10MB(不同平台略有差异);
      • 存储为字符串类型,对象需用 JSON.stringify 转换;
      • 清理微信缓存时可能被删除,不适合存关键数据。
  3. 小程序如何实现下拉刷新和上拉加载更多?

    • 下拉刷新

      1. 在页面 json 中配置 { "enablePullDownRefresh": true }

      2. 在 page.js 中实现 onPullDownRefresh 钩子:

        onPullDownRefresh() {
          // 拉取新数据
          this.fetchData().then(() => {
            wx.stopPullDownRefresh(); // 停止刷新动画
          });
        }
        
    • 上拉加载更多

      1. 在 page.js 中实现 onReachBottom 钩子(距离底部 50px 时触发):
        onReachBottom() {
          if (!this.data.isLoading && this.data.hasMore) {
            this.setData({ isLoading: true });
            this.fetchMoreData().then(() => {
              this.setData({ isLoading: false });
            });
          }
        }
        

六、跨平台与框架

  1. Taro、UniApp 等跨平台框架的原理?相比原生开发有什么优缺点?

    • 原理:通过一套代码编译为不同平台的小程序(微信、支付宝、抖音等)及 H5、App,底层通过抽象层适配各平台 API

    • 优点:

      • 一次开发多端运行,降低跨平台开发成本;
      • 支持 React/Vue 语法,前端开发者学习成本低
      • 内置工程化工具(如路由、状态管理),开发效率高。
    • 缺点:

      • 框架本身有学习成本,且可能存在平台特性适配不全的问题
      • 编译后的代码体积可能比原生大,性能略低
      • 调试复杂(需在各平台分别测试)。

这些问题覆盖了小程序开发的核心知识点,结合你的前端基础,重点理解 “小程序与 H5 的差异”“生命周期”“性能优化” 和 “实战场景” 即可应对大部分面试。如果需要某类问题的更深入解析,可以进一步提问!

uniapp详细讲解