小程序讲解
作为前端程序员,你已经掌握了 HTML、CSS、JavaScript 等核心技能,学习小程序开发会非常容易上手 —— 因为小程序的开发思想和前端高度一致,只是在语法规范、API 生态和工具链上有平台特定的规则。以下从 核心语法、开发流程、技术栈、进阶技巧 四个维度,为你详细讲解小程序开发知识:
一、小程序与前端开发的核心差异(先搞懂 “不一样” 的地方)
-
语法规范
- 前端用
HTML写结构,小程序用平台自定义标签(如微信用WXML,支付宝用AXML),标签名更语义化(如<view>对应<div>,<text>对应<span>,<image>对应<img>)。 - 前端用
CSS写样式,小程序用平台样式表(如微信WXSS、支付宝ACSS),支持大部分 CSS 语法,但新增了rpx 单位(自适应屏幕,1rpx = 屏幕宽度 / 750,解决多设备适配问题)。 - 逻辑层仍用 JavaScript,但小程序对 ES6+ 语法的支持需看平台版本(通常支持
async/await、箭头函数,但部分老版本不支持import需用require)。
- 前端用
-
运行环境
- 前端运行在浏览器中,受浏览器安全策略限制(如跨域需后端配置 CORS);
- 小程序运行在平台的 沙箱环境 中(如微信的 X5 内核),有独立的 API 体系(如调用摄像头、支付需用平台提供的 API),跨域请求需在平台后台配置 “合法域名”。
-
生命周期
- 前端页面生命周期由浏览器控制(
load、DOMContentLoaded等); - 小程序有 应用生命周期(如微信的
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.js、my-button.wxml等)。 -
注册组件:在页面的
index.json中声明:{ "usingComponents": { "my-button": "/components/my-button/my-button" } } -
使用组件:在
index.wxml中直接引用<my-button text="点击" bind:click="onBtnClick" />,通过properties接收参数,triggerEvent触发自定义事件。
三、开发工具与流程(以微信小程序为例)
-
工具准备
- 下载 微信开发者工具(集成编辑器、模拟器、调试器)。
- 注册微信公众平台账号,获取
appid(测试可先用 “测试号”)。
-
开发流程
- 新
建项目:选择小程序项目,输入
appid(或测试号),选择目录。 - 编写代码:在编辑器中写
wxml、wxss、js,实时在模拟器预览。 - 调试:用 “调试器” 查看 console、network、DOM 结构(类似 Chrome DevTools)。
- 预览:通过工具生成二维码,用手机微信扫码查看真实效果。
- 发布:
上传代码到微信公众平台,审核通过后发布上线。
- 新
建项目:选择小程序项目,输入
四、前端程序员的进阶技巧(复用你的前端经验)
-
样式复用
- 用
@import导入公共样式(如@import "/styles/common.wxss";)。 - 利用
less/sass编写样式:在开发者工具中开启 “使用 npm 模块”,通过gulp或webpack将 less 编译为 wxss(类似前端工程化)。
- 用
-
状态管理
- 简单场景:用
getApp()获取全局 App 实例,在app.js中定义全局数据(如用户信息)。 - 复杂场景:引入前端常用的状态管理库(如
mobx-miniprogram或简化版redux),管理跨页面数据。
- 简单场景:用
-
跨平台开发(一次开发多端运行)
- 如果你需要同时开发微信、支付宝、抖音小程序,可使用 Taro 或 UniApp(基于 React/Vue 语法,编译到多端),复用你已有的 React/Vue 技能。
-
性能优化(小程序特有)
- 减少
setData调用:setData会触发页面重渲染,避免频繁调用,可合并数据后一次性更新。 - 图片优化:用
image组件的lazy-load懒加载,通过wx.getImageInfo预加载大图。 - 分包加载:将大项目拆分为 “主包 + 分包”,用户进入对应页面才下载分包,减少首次启动时间。
- 减少
五、其他平台小程序的差异(快速迁移)
- 支付宝小程序:语法类似微信,但标签名和 API 有差异(如
a:if替代wx:if,my.request替代wx.request),侧重支付和生活服务场景。 - 抖音 / 头条小程序:基于字节跳动生态,支持短视频挂载,API 前缀为
tt.(如tt.request)。 - 统一规律:所有平台的小程序都遵循 “结构 - 样式 - 逻辑” 分离的思想,核心差异在 API 前缀和平台特有功能(如微信的社交分享、支付宝的芝麻信用),熟悉一个平台后,迁移到其他平台只需适配 API 即可。
作为前端开发者,你可以把小程序看作 “前端技术的子集 + 平台特定 API”,重点掌握 数据绑定、生命周期、组件化、平台 API 这四点,就能快速上手开发。如果需要具体场景的实战示例(如登录功能、支付集成),可以进一步提问!
高频面试题
小程序开发作为前端领域的重要分支,面试中常围绕基础语法、框架特性、性能优化、实战场景等展开。以下是高频面试题及详细解析,结合前端开发者的知识体系帮你快速掌握核心考点:
一、基础概念与语法
-
小程序与普通网页(H5)的区别?
-
运行环境:小程序运行在平台自研的沙箱环境(如微信的 X5 内核),H5 运行在浏览器中; -
权限:小程序可调用平台原生能力(如摄像头、支付、地理位置),H5 受浏览器安全限制,权限较少; -
更新机制:小程序需提交审核发布,H5 可实时更新。 -
资源加载:小程序有体积限制(通常 2MB 内,分包可扩展),加载更快;H5 依赖网络加载,受网速影响大;
-
路由管理:小程序内置路由(
wx.navigateTo等),H5 需手动实现或用vue-router等库;
-
-
小程序的目录结构有哪些核心文件?各自作用是什么?
-
全局文件:
app.js:应用入口,定义应用生命周期(onLaunch、onShow、onHide)和全局数据;app.json:全局配置(页面路径、窗口样式、导航栏、tabBar 等);app.wxss:全局样式,作用于所有页面。
-
页面文件(每个页面一个目录):
page.js:页面逻辑(数据、生命周期、事件方法);page.wxml:页面结构(类似 HTML,用自定义标签如<view>、<text>);page.wxss:页面样式(支持 rpx 单位,优先级高于全局样式);page.json:页面配置(覆盖全局配置,如单独设置导航栏标题)。
-
-
小程序的生命周期有哪些?应用生命周期和页面生命周期的区别?
-
应用生命周期(
app.js中定义):onLaunch:小程序初始化完成(全局只触发一次);onShow:小程序切入前台时触发(如从后台切换回来);onHide:小程序切入后台时触发(如按手机 Home 键)。
-
页面生命周期(
page.js中定义):onLoad:页面加载时触发(接收路由参数,只触发一次);onShow:页面显示时触发(每次切换到该页面都会触发);onReady:页面初次渲染完成(可操作 DOM,只触发一次);onHide:页面隐藏时触发(如跳转到其他页面);onUnload:页面卸载时触发(如返回上一页并关闭当前页)。
-
区别:应用生命周期贯穿小程序全局,页面生命周期只针对单个页面的创建到销毁。
-
二、核心特性与 API
-
小程序的数据绑定原理?
setData有什么注意事项?-
原理:类似 Vue 的单向数据绑定,通过
{{ }}在 WXML 中绑定data中的数据,当data变化时,视图自动更新。 -
setData注意事项:必须用this.setData({ key: value })更新数据,直接修改this.data不会触发视图更新;- 是异步操作,修改后不能立即获取更新后的数据(可在回调中处理:
this.setData({ ... }, () => { ... })); 避免频繁调用(会触发页面重渲染),建议合并数据后一次性更新;- 支持路径形式修改对象 / 数组(如
this.setData({ 'user.name': 'xxx' }))。
-
-
小程序的路由跳转方式有哪些?区别是什么?
-
主要方式:
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 限制、栈管理机制不同。
-
-
小程序如何发起网络请求?有哪些限制?
-
用
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配置。
- 只能请求
-
-
小程序的
wx:if和hidden的区别?如何选择?-
wx:if:动态创建 / 销毁元素,条件为false时不渲染该节点(惰性渲染); -
hidden:通过display: none隐藏元素,节点始终存在于 DOM 中。 -
选择:
- 频繁切换显示 / 隐藏时用
hidden(避免频繁创建 / 销毁节点,性能更好); - 条件很少变化时用
wx:if(减少初始渲染的节点数)。
- 频繁切换显示 / 隐藏时用
-
三、组件化开发
-
小程序如何自定义组件?组件间如何通信?
-
自定义组件步骤:
- 创建组件目录(如
components/my-btn),包含my-btn.js、my-btn.wxml、my-btn.wxss、my-btn.json; - 在组件
json中声明{ "component": true }; - 在使用组件的页面
json中注册:{ "usingComponents": { "my-btn": "/components/my-btn/my-btn" } }; - 在页面
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存储数据(适合简单场景)。
- 父传子:通过
-
-
小程序的
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>
-
四、性能优化
-
小程序的性能优化方法有哪些?
-
启动优化:
- 减小主包体积(主包控制在 2MB 内),用分包加载(
subPackages配置,进入分包页面才下载); - 预加载关键资源(
preloadRule配置分包预加载)。
- 减小主包体积(主包控制在 2MB 内),用分包加载(
-
渲染优化:
- 减少
setData调用频率(合并数据更新); setData只传需要修改的字段(避免传递整个大对象);- 列表渲染用
wx:key(提高重排效率),避免渲染大量数据(可分页加载)。
- 减少
-
资源优化:
- 图片压缩(用
image组件的mode裁剪,避免大图缩放); - 图片懒加载(
lazy-load: true); - 复用
wx.createCanvasContext等实例,避免频繁创建。
- 图片压缩(用
-
代码优化:
- 移除未使用的代码和资源;
- 用
function声明方法(箭头函数可能导致this指向问题); - 避免在
onShow中做 heavy 操作(影响页面切换流畅度)。
-
-
小程序的分包加载原理?如何配置?
-
原理:将小程序拆分为 “主包” 和 “分包”,主包包含启动页和公共资源,分包包含其他页面。用户首次启动只下载主包,进入分包页面时才下载对应分包,减少首次启动时间。
-
配置(
app.json):{ "pages": ["pages/index/index"], // 主包页面 "subPackages": [ { "root": "pages/detail", // 分包根目录 "pages": ["index/index"] // 分包内页面 } ], "preloadRule": { // 预加载配置(进入首页时预加载详情分包) "pages/index/index": { "network": "all", "packages": ["pages/detail"] } } }
-
五、实战场景与问题解决
-
小程序如何实现登录功能?
-
流程(以微信小程序为例):
- 调用
wx.login()获取临时登录凭证code; - 将
code发送到后端,后端通过微信接口(https://api.weixin.qq.com/sns/jscode2session)换取openid(用户唯一标识)和session_key; - 后端生成自定义登录态(如
token),返回给小程序; - 小程序存储
token(wx.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); } }); } } });
-
-
小程序如何处理本地存储?有哪些限制?
-
用
wx.setStorageSync(同步)或wx.setStorage(异步)存储数据:wx.setStorageSync('userInfo', { name: '张三' }); // 存储 const userInfo = wx.getStorageSync('userInfo'); // 读取 wx.removeStorageSync('userInfo'); // 删除 -
限制:
- 单个 key 最大 1MB,总存储上限约 10MB(不同平台略有差异);
- 存储为字符串类型,对象需用
JSON.stringify转换; - 清理微信缓存时可能被删除,不适合存关键数据。
-
-
小程序如何实现下拉刷新和上拉加载更多?
-
下拉刷新:
-
在页面
json中配置{ "enablePullDownRefresh": true }; -
在
page.js中实现onPullDownRefresh钩子:onPullDownRefresh() { // 拉取新数据 this.fetchData().then(() => { wx.stopPullDownRefresh(); // 停止刷新动画 }); }
-
-
上拉加载更多:
- 在
page.js中实现onReachBottom钩子(距离底部 50px 时触发):onReachBottom() { if (!this.data.isLoading && this.data.hasMore) { this.setData({ isLoading: true }); this.fetchMoreData().then(() => { this.setData({ isLoading: false }); }); } }
- 在
-
六、跨平台与框架
-
Taro、UniApp 等跨平台框架的原理?相比原生开发有什么优缺点?
-
原理:通过一套代码编译为不同平台的小程序(微信、支付宝、抖音等)及 H5、App,底层通过抽象层适配各平台 API。
-
优点:
- 一次开发多端运行,降低跨平台开发成本;
- 支持 React/Vue 语法,前端开发者学习成本低;
- 内置工程化工具(如路由、状态管理),开发效率高。
-
缺点:
- 框架本身有学习成本,且可能存在平台特性适配不全的问题;
- 编译后的代码体积可能比原生大,性能略低;
- 调试复杂(需在各平台分别测试)。
-
这些问题覆盖了小程序开发的核心知识点,结合你的前端基础,重点理解 “小程序与 H5 的差异”“生命周期”“性能优化” 和 “实战场景” 即可应对大部分面试。如果需要某类问题的更深入解析,可以进一步提问!