微信小程序面试40道题目加解析
解析微信小程序是微信生态内的轻量级应用,无需下载安装即可使用,基于微信提供的框架运行。免安装 / 触手可及:通过微信扫码、搜索等方式直接打开,降低用户使用门槛;用完即走:不占用手机存储空间,关闭后不常驻后台(除非有后台运行能力配置);技术栈独特:采用 WXML(视图层)、WXSS(样式层)、JS(逻辑层)、JSON(配置层),而非传统 H5 技术栈;原生能力调用:可直接调用微信原生 API(如支付
一、基础概念与核心配置(1-10 题)
1. 什么是微信小程序?它的核心特性有哪些?
解析:
微信小程序是微信生态内的轻量级应用,无需下载安装即可使用,基于微信提供的框架运行。核心特性包括:
- 免安装 / 触手可及:通过微信扫码、搜索等方式直接打开,降低用户使用门槛;
- 用完即走:不占用手机存储空间,关闭后不常驻后台(除非有后台运行能力配置);
- 技术栈独特:采用 WXML(视图层)、WXSS(样式层)、JS(逻辑层)、JSON(配置层),而非传统 H5 技术栈;
- 原生能力调用:可直接调用微信原生 API(如支付、定位、相机),功能比 H5 更强大;
- 性能接近原生:拥有独立的渲染线程和逻辑线程,避免单线程阻塞,加载速度快于 H5。
2. 小程序与 H5 的主要区别是什么?
解析:核心区别集中在运行环境、权限、性能等维度,具体如下:
维度 |
微信小程序 |
H5 |
运行环境 |
微信内置浏览器(基于 Chromium 内核优化) |
普通浏览器(如 Chrome、Safari 等) |
权限能力 |
可调用微信原生 API(支付、通讯录、蓝牙) |
仅能使用浏览器提供的 API(如定位需用户授权) |
性能 |
双线程(渲染 / 逻辑分离),无 DOM 操作阻塞 |
单线程(JS 与 DOM 渲染互斥,易卡顿) |
缓存机制 |
提供 wx.setStorage 等原生缓存 API,容量约 10MB |
依赖浏览器缓存(localStorage、sessionStorage),容量约 5MB |
发布与审核 |
需通过微信公众平台审核,发布后实时生效 |
无需审核,部署到服务器即可访问 |
3. 小程序的核心配置文件有哪些?各自的作用是什么?
解析:小程序有 4 类核心配置文件,作用分工明确:
- app.json:全局配置,控制小程序的整体行为,如页面路径(pages)、窗口样式(window)、底部 TabBar(tabBar)、网络超时时间(networkTimeout)等;
示例:"pages": ["pages/index/index", "pages/logs/logs"] 定义小程序的所有页面路径,第一个路径为首页。
- page.json:页面单独配置,覆盖 app.json 中 window 节点的配置,如当前页面的导航栏标题(navigationBarTitleText)、是否允许下拉刷新(enablePullDownRefresh)等;
- app.js:小程序入口逻辑文件,定义 App 实例,处理应用生命周期(如 onLaunch、onShow),并可全局存储数据(如用户信息);
- project.config.json:项目配置文件,记录开发者工具的个性化设置(如项目名称、AppID、编译配置),便于团队协作时统一开发环境。
4. 小程序的目录结构中,pages 文件夹下的每个页面通常包含哪些文件?
解析:每个页面需包含 4 个同名文件(后缀不同),缺一不可:
- .wxml:视图层文件,类似 HTML,用于定义页面结构,支持小程序内置组件(如 <view>、<button>)和模板语法(如 {{}} 数据绑定);
- .wxss:样式层文件,类似 CSS,扩展了 rpx 自适应单位(1rpx = 屏幕宽度 / 750),且支持 @import 导入外部样式;
- .js:逻辑层文件,定义 Page 实例,处理页面生命周期(如 onLoad、onTap)、事件绑定(如 bindtap)和数据管理(data 节点);
- .json:页面配置文件,仅能配置 window 相关属性,用于自定义当前页面的导航栏、背景色等。
5. 小程序的 “双线程模型” 是什么?它解决了什么问题?
解析:
- 双线程模型定义:小程序分为 渲染线程(负责页面渲染,运行在视图层)和 逻辑线程(负责业务逻辑,运行在逻辑层),两者通过微信原生的 “JSBridge” 通信,数据传递需通过 setData 实现。
- 解决的问题:传统 H5 是单线程模型(JS 执行与 DOM 渲染互斥),若 JS 执行时间过长,会导致页面卡顿。双线程模型将逻辑与渲染分离,避免逻辑层 JS 阻塞渲染层,提升页面流畅度;同时,逻辑层无法直接操作 DOM,也避免了 XSS 等安全风险。
6. 小程序的 AppID 有什么作用?测试环境和正式环境的 AppID 有区别吗?
解析:
- AppID 作用:AppID 是小程序的唯一标识,用于:① 关联微信公众平台账号;② 调用微信开放平台 API(如支付、登录、分享);③ 区分开发环境与正式环境;④ 小程序发布审核的唯一凭证。
- 环境区别:
-
- 测试环境(测试号 AppID):仅用于开发调试,无法调用正式版 API(如支付、获取用户手机号),且小程序无法被非开发者账号搜索到;
-
- 正式环境(已认证账号的 AppID):需通过微信公众平台认证(个人号 / 企业号),可调用所有开放 API,发布后可被所有微信用户访问。
7. 小程序的 “页面栈” 是什么?最多能容纳多少个页面?
解析:
- 页面栈定义:小程序通过栈(先进后出)管理页面跳转,每次用 wx.navigateTo 打开新页面时,页面会入栈;点击返回按钮或调用 wx.navigateBack 时,页面会出栈。
- 容量限制:页面栈最多容纳 10 个页面,若超过限制,调用 wx.navigateTo 会失败。此时需用 wx.redirectTo(关闭当前页面后入栈)或 wx.switchTab(清空栈后跳转到 TabBar 页面)规避。
- 注意:可通过 getCurrentPages() 获取当前页面栈实例,但不建议修改栈内数据(可能导致页面状态异常),仅用于获取页面路径、参数等信息。
8. 小程序的 WXSS 与 CSS 有哪些区别?
解析:WXSS 是 CSS 的扩展,新增了 3 个核心特性:
- 自适应单位 rpx:CSS 用 px(固定像素),WXSS 用 rpx(相对像素),1rpx = 屏幕宽度 / 750,适配所有设备(如 750px 设计稿中,1rpx = 1px;375px 手机中,1rpx = 0.5px);
- 样式隔离:默认情况下,页面的 WXSS 仅作用于当前页面,组件的 WXSS 仅作用于组件内部(通过 styleIsolation 配置可修改隔离规则),避免样式污染;
- 全局样式与局部样式:app.wxss 是全局样式,作用于所有页面;页面的 .wxss 是局部样式,优先级高于全局样式(若选择器权重相同)。
此外,WXSS 不支持 CSS 的部分属性(如 background-attachment、marquee)。
9. 小程序的 JSON 配置中,tabBar 的作用是什么?核心属性有哪些?
解析:
- tabBar 作用:用于实现小程序底部 / 顶部的导航栏(最多支持 5 个 Tab),点击 Tab 可切换页面,且切换时会清空页面栈(仅保留当前 Tab 页面)。
- 核心属性:
-
- list:必填,Tab 列表(数组,最少 2 个、最多 5 个),每个 Tab 包含 pagePath(页面路径,必须在 pages 中定义)、text(Tab 文字)、iconPath(未选中时图标路径)、selectedIconPath(选中时图标路径);
-
- position:可选,Tab 位置(bottom 或 top),默认 bottom;若为 top,则不显示图标;
-
- color:可选,未选中 Tab 文字颜色;
-
- selectedColor:可选,选中 Tab 文字颜色;
-
- backgroundColor:可选,Tab 背景色;
-
- borderStyle:可选,Tab 边框颜色(仅支持 black 或 white)。
10. 小程序的 “分包加载” 是什么?它的优势和配置方式是什么?
解析:
- 分包加载定义:将小程序的代码拆分为 “主包” 和 “分包”,主包包含首页和公共资源(如 app.js、app.json),分包包含其他页面;用户打开小程序时,先加载主包,进入分包页面时再加载对应分包,减少初始加载时间。
- 优势:① 降低主包体积(主包默认限制 2MB,分包总限制 20MB);② 提升首屏加载速度,优化用户体验。
- 配置方式:在 app.json 中添加 subpackages 节点:
"subpackages": [
{
"root": "packageA", // 分包根目录
"name": "packageA", // 分包名称(可选)
"pages": ["pages/cat/cat", "pages/dog/dog"] // 分包内页面路径
}
]
若需指定某个分包为 “独立分包”(可单独加载,不依赖主包),需在分包配置中添加 "independent": true。
二、生命周期与页面交互(11-20 题)
11. 小程序的应用生命周期有哪些?各自的触发时机是什么?
解析:应用生命周期在 app.js 中通过 App 实例定义,共 4 个:
- onLaunch:小程序初始化完成时触发(全局仅触发 1 次),可用于初始化全局数据(如获取用户登录状态)、调用启动接口;
- onShow:小程序启动或从后台切换到前台时触发(每次切换都会触发),可用于更新页面数据(如刷新用户信息);
- onHide:小程序从前台切换到后台时触发(如用户按 Home 键、打开其他 App),可用于保存当前页面状态(如暂停定时器);
- onError:小程序发生脚本错误或 API 调用失败时触发,可用于错误上报(如上报到 Sentry)。
12. 小程序的页面生命周期有哪些?触发顺序是什么?
解析:页面生命周期在页面的 .js 中通过 Page 实例定义,核心生命周期及触发顺序如下(以首次打开页面为例):
- onLoad:页面加载时触发(仅触发 1 次),可接收页面跳转的参数(如 options.id),常用于初始化数据(如调用接口获取详情);
- onShow:页面显示时触发(每次切换到该页面都会触发),可用于刷新页面数据(如返回页面时重新请求列表);
- onReady:页面初次渲染完成时触发(仅触发 1 次),可用于操作页面 DOM 或组件(如获取组件实例 this.selectComponent('#myComponent'));
- onHide:页面隐藏时触发(如跳转到其他页面、切换到后台),可用于暂停操作(如暂停视频播放);
- onUnload:页面卸载时触发(如调用 wx.redirectTo、wx.navigateBack 关闭页面),可用于清理资源(如清除定时器、取消接口请求)。
13. 应用生命周期 onLaunch 和页面生命周期 onLoad 哪个先触发?为什么?
解析:onLaunch 先触发。
原因:小程序初始化流程为:① 启动小程序 → ② 执行 app.js 中的 App 实例 → ③ 触发 onLaunch(初始化完成) → ④ 根据 app.json 中的 pages 配置加载首页 → ⑤ 执行首页的 Page 实例 → ⑥ 触发首页的 onLoad。因此,应用初始化完成(onLaunch)后,才会加载页面并触发页面的 onLoad。
14. 小程序中如何实现页面跳转?有哪些跳转方式?各自的区别是什么?
解析:小程序提供 5 种页面跳转方式,核心区别在于是否保留当前页面、是否能跳转到 TabBar 页面:
跳转 API |
是否保留当前页面 |
是否能跳转到 TabBar 页面 |
页面栈变化 |
wx.navigateTo |
是(入栈) |
否 |
栈长度 + 1(最多 10 层) |
wx.redirectTo |
否(出栈后入栈) |
否 |
栈长度不变(替换当前页面) |
wx.switchTab |
否(清空栈) |
是(仅能跳转到 TabBar) |
栈仅保留目标 Tab 页面 |
wx.reLaunch |
否(清空栈) |
是 |
栈仅保留目标页面 |
wx.navigateBack |
否(出栈) |
否 |
栈长度 - 1(可指定返回层数) |
示例:跳转到非 TabBar 页面用 wx.navigateTo,跳转到 TabBar 页面必须用 wx.switchTab。 |
15. 小程序中如何传递页面参数?接收参数的方式是什么?
解析:传递参数主要通过 URL 拼接和全局存储两种方式:
- URL 拼接(常用,适用于跳转时传递少量数据):
-
- 传递:跳转时在 url 后拼接参数(键值对形式,用 ? 分隔参数,& 分隔多个参数),如:
wx.navigateTo({
url: '/pages/detail/detail?id=123&name=苹果' // 传递 id=123、name=苹果
})
-
- 接收:在目标页面的 onLoad 生命周期中通过 options 参数获取,如:
onLoad(options) {
console.log(options.id); // 123
console.log(options.name); // 苹果
}
- 全局存储(适用于传递大量数据或跨页面共享数据):
-
- 传递:在 app.js 中定义全局数据,如 globalData: { userInfo: {} },然后在页面中通过 getApp().globalData.userInfo = data 赋值;
-
- 接收:在目标页面中通过 const app = getApp(); console.log(app.globalData.userInfo) 获取。
16. 小程序中如何实现下拉刷新?需要配置哪些属性?
解析:实现下拉刷新需两步配置:
- 开启下拉刷新:
-
- 全局开启:在 app.json 的 window 节点中设置 "enablePullDownRefresh": true(所有页面生效);
-
- 页面单独开启:在页面的 .json 文件中设置 "enablePullDownRefresh": true(仅当前页面生效,优先级高于全局)。
- 处理下拉刷新逻辑:在页面的 .js 中实现 onPullDownRefresh 生命周期,用于触发刷新操作(如重新请求接口),刷新完成后需调用 wx.stopPullDownRefresh() 关闭刷新动画,示例:
onPullDownRefresh() {
// 调用接口重新获取数据
this.getListData().then(() => {
// 关闭下拉刷新动画
wx.stopPullDownRefresh();
});
}
此外,可通过 backgroundColor(下拉刷新区域背景色)和 backgroundTextStyle(刷新图标颜色,仅支持 dark 或 light)自定义刷新样式。
17. 小程序中如何实现上拉加载更多?核心逻辑是什么?
解析:上拉加载更多依赖页面的 onReachBottom 生命周期(页面滚动到底部时触发),核心逻辑如下:
- 配置触发距离:在页面的 .json 中设置 onReachBottomDistance(默认 50px,即距离底部 50px 时触发),如 "onReachBottomDistance": 100;
- 实现加载逻辑:在页面的 .js 中定义 onReachBottom 方法,需处理 “分页参数” 和 “加载状态”(避免重复请求),示例:
Page({
data: {
list: [],
page: 1, // 当前页码
pageSize: 10, // 每页条数
isLoading: false, // 是否正在加载
hasMore: true // 是否还有更多数据
},
onReachBottom() {
// 若正在加载或无更多数据,直接返回
if (this.data.isLoading || !this.data.hasMore) return;
this.setData({ isLoading: true });
// 调用分页接口
this.getListData(this.data.page + 1).then(res => {
const newList = this.data.list.concat(res.data);
this.setData({
list: newList,
page: this.data.page + 1,
isLoading: false,
hasMore: res.data.length === this.data.pageSize // 若返回数据少于 pageSize,说明无更多
});
});
}
});
18. 小程序中 setData 的作用是什么?使用时需要注意哪些问题?
解析:
- setData 作用:用于修改页面的 data 数据,并触发页面重新渲染(逻辑层数据传递到视图层)。直接修改 this.data 不会触发渲染,必须通过 setData。
- 注意事项:
-
- 异步更新:setData 是异步操作,修改后不能立即获取最新数据,需在 setData 的第二个参数(回调函数)中处理后续逻辑,如:
this.setData({ count: 1 }, () => {
console.log(this.data.count); // 1(正确,回调中获取最新值)
});
console.log(this.data.count); // 0(错误,同步代码中获取旧值)
-
- 避免频繁调用:每次 setData 都会触发渲染,频繁调用(如循环中调用)会导致页面卡顿,建议合并数据后一次性调用;
-
- 不传递冗余数据:仅传递需要修改的字段,避免传递整个 data 对象(如 this.setData({ list: newList }) 而非 this.setData({ data: this.data }));
-
- 不修改页面栈数据:禁止通过 setData 修改 getCurrentPages() 返回的页面栈实例,可能导致页面状态异常。
19. 小程序中如何绑定事件?事件绑定的方式有哪些?
解析:小程序的事件绑定通过 bind 或 catch 前缀实现,核心区别在于是否阻止事件冒泡:
- 绑定方式:
-
- bind + 事件名:绑定事件,不阻止冒泡(如 bindtap 点击事件、bindinput 输入事件);
-
- catch + 事件名:绑定事件,阻止冒泡(如 catchtap,常用于避免父组件事件被触发);
-
- mut-bind + 事件名:绑定事件,仅触发当前组件的事件,不触发父组件和子组件的同类型事件(较少用)。
- 示例(点击事件):
-
- WXML:<button bindtap="handleTap" data-id="123">点击</button>(data-* 用于传递自定义参数);
-
- JS:
handleTap(e) {
// 通过 e.currentTarget.dataset 获取自定义参数
console.log(e.currentTarget.dataset.id); // 123
}
- 常用事件:tap(点击)、input(输入)、change(值改变)、longpress(长按)、scroll(滚动)。
20. 小程序中如何实现表单提交与校验?
解析:表单提交需结合 <form> 组件和 form-type 属性,校验可通过自带属性或自定义逻辑实现:
- 表单结构(WXML):
<form bindsubmit="handleSubmit">
<!-- 输入框,通过 name 标识字段 -->
<view class="form-item">
<label>用户名:</label>
<input name="username" placeholder="请输入用户名" required /> <!-- required 自带非空校验 -->
</view>
<view class="form-item">
<label>手机号:</label>
<input name="phone" placeholder="请输入手机号" type="number" bindinput="handlePhoneInput" />
</view>
<!-- 提交按钮,必须设置 form-type="submit" -->
<button form-type="submit">提交</button>
</form>
- 表单校验与提交(JS):
Page({
data: {
phone: ''
},
// 实时校验手机号格式
handlePhoneInput(e) {
const phone = e.detail.value;
// 正则校验手机号(11位数字)
if (!/^1[3-9]\d{9}$/.test(phone) && phone) {
wx.showToast({ title: '手机号格式错误', icon: 'none' });
}
this.setData({ phone });
},
// 表单提交
handleSubmit(e) {
const { username, phone } = e.detail.value; // 获取表单所有字段值
// 自定义校验
if (!username) {
wx.showToast({ title: '请输入用户名', icon: 'none' });
return;
}
if (!/^1[3-9]\d{9}$/.test(phone)) {
wx.showToast({ title: '请输入正确的手机号', icon: 'none' });
return;
}
// 校验通过,调用提交接口
wx.request({
url: 'https://api.example.com/submit',
method: 'POST',
data: { username, phone },
success(res) {
wx.showToast({ title: '提交成功' });
}
});
}
});
- 核心要点:① 表单按钮需设置 form-type="submit";② 通过 e.detail.value 获取所有表单字段;③ 可结合 required(非空)、type(输入类型)做基础校验,复杂校验需自定义正则。
三、组件开发与通信(21-30 题)
21. 小程序的组件分为哪几类?自定义组件的创建步骤是什么?
解析:
- 组件分类:① 内置组件(微信原生提供,如 <view>、<button>、<swiper>);② 自定义组件(开发者自行开发,可复用);③ 插件组件(第三方提供,需在 app.json 中引入)。
- 自定义组件创建步骤:
-
- 创建组件目录:在项目根目录新建 components 文件夹,再新建组件文件夹(如 my-component);
-
- 创建组件文件:在组件文件夹中新建 4 个文件(my-component.wxml、my-component.wxss、my-component.js、my-component.json);
-
- 配置组件声明:在组件的 .json 文件中设置 "component": true,声明该文件夹为组件,如:
{
"component": true,
"usingComponents": {} // 若组件依赖其他组件,需在此引入
}
-
- 编写组件逻辑:在组件的 .js 中用 Component 构造器定义组件,而非 Page,如:
Component({
properties: {}, // 组件属性(外部传入)
data: {}, // 组件内部数据
methods: {} // 组件方法
});
-
- 使用组件:在需要使用组件的页面的 .json 中引入组件,如:
{
"usingComponents": {
"my-component": "/components/my-component/my-component" // 键为组件名,值为组件路径
}
}
-
- 在页面中使用:在页面的 .wxml 中直接使用组件标签 <my-component></my-component>。
22. 自定义组件的 properties 和 data 有什么区别?如何传递属性给组件?
解析:
- 区别:
维度 |
properties |
data |
作用 |
接收外部传入的属性(类似组件的 “参数”) |
组件内部的私有数据(类似页面的 data) |
可修改性 |
可通过外部修改(页面调用组件时传递),也可通过 this.setData 内部修改 |
仅能通过组件内部 this.setData 修改 |
定义方式 |
需指定类型(如 String、Number)、默认值,支持校验 |
直接定义键值对,无需指定类型 |
- 传递属性给组件:
-
- 组件定义 properties:在组件的 .js 中声明属性,示例:
Component({
properties: {
// 简单声明(指定类型)
title: String,
// 完整声明(指定类型、默认值、校验)
count: {
type: Number, // 类型(必填)
value: 0, // 默认值(可选)
observer(newVal, oldVal) { // 属性值变化时的回调(可选)
console.log('count 从', oldVal, '变为', newVal);
}
}
}
});
-
- 页面传递属性:在页面的 .wxml 中使用组件时,通过 “属性名 = 值” 传递,支持数据绑定,示例:
<!-- 传递静态值 -->
<my-component title="Hello"></my-component>
<!-- 传递动态值(页面 data 中的 count 变量) -->
<my-component count="{{count}}"></my-component>
23. 自定义组件如何向父组件传递事件?父组件如何响应?
解析:组件向父组件传递事件通过 触发自定义事件 实现,步骤如下:
- 组件触发自定义事件:在组件的方法中,通过 this.triggerEvent('事件名', 传递的数据, 事件选项) 触发事件,示例:
Component({
methods: {
handleClick() {
// 触发自定义事件 "change",传递数据 { value: 100 }
this.triggerEvent('change', { value: 100 });
}
}
});
- 父组件绑定事件并响应:在页面的 .wxml 中,通过 “bind + 自定义事件名” 绑定事件,然后在页面的 .js 中实现响应方法,示例:
-
- WXML:<my-component bindchange="handleComponentChange"></my-component>;
-
- JS:
Page({
handleComponentChange(e) {
// 通过 e.detail 获取组件传递的数据
console.log('组件传递的值:', e.detail.value); // 100
}
});
- 事件选项:triggerEvent 的第三个参数是事件选项(如 bubbles 是否冒泡、composed 是否穿透组件边界),默认均为 false。
24. 自定义组件的生命周期有哪些?与页面生命周期有什么区别?
解析:
- 自定义组件生命周期:通过 Component 构造器的 lifetimes 节点定义,核心生命周期如下:
-
- created:组件实例创建时触发(仅触发 1 次),此时无法访问 this.data 和 DOM,可用于初始化数据;
-
- attached:组件实例挂载到页面节点树时触发(仅触发 1 次),可访问 this.data 和 DOM,常用于初始化 DOM 操作;
-
- ready:组件渲染完成时触发(仅触发 1 次),可用于获取组件尺寸、操作渲染后的 DOM;
-
- moved:组件实例被移动到另一个节点树时触发(较少用);
-
- detached:组件实例从页面节点树中移除时触发(如页面卸载、组件被隐藏),可用于清理资源(如清除定时器);
-
- error:组件发生错误时触发(如脚本错误)。
- 与页面生命周期的区别:
-
- 组件生命周期更关注 “组件实例的创建、挂载、卸载”,页面生命周期更关注 “页面的加载、显示、渲染”;
-
- 组件无 onLoad、onShow 等页面特有的生命周期,但可通过 pageLifetimes 节点监听所在页面的生命周期(如页面的 onShow、onHide),示例:
Component({
pageLifetimes: {
show() {
// 所在页面显示时触发
},
hide() {
// 所在页面隐藏时触发
}
}
});
25. 小程序的 slot 插槽是什么?如何使用?支持多插槽吗?
解析:
- slot 作用:用于在自定义组件中预留 “占位符”,允许父组件向组件内部插入自定义内容(类似 Vue 的 slot),实现组件内容的灵活定制。
- 基础使用步骤:
-
- 组件中定义 slot:在组件的 .wxml 中添加 <slot> 标签,示例:
<!-- 组件 my-component.wxml -->
<view class="component-container">
<!-- 插槽:父组件可插入内容到这里 -->
<slot></slot>
</view>
-
- 父组件插入内容:在使用组件时,直接在组件标签内写入内容,内容会替换组件中的 <slot>,示例:
<!-- 页面 wxml -->
<my-component>
<!-- 插入到组件 slot 中的内容 -->
<text>这是父组件插入的内容</text>
<button bindtap="handleClick">父组件的按钮</button>
</my-component>
- 多插槽支持:小程序支持多插槽,但需手动开启:
-
- 组件配置多插槽:在组件的 .js 中设置 options: { multipleSlots: true },示例:
Component({
options: {
multipleSlots: true // 开启多插槽
}
});
-
- 组件定义命名 slot:通过 name 属性区分不同插槽,示例:
<!-- 组件 my-component.wxml -->
<view>
<!-- 头部插槽 -->
<slot name="header"></slot>
<!-- 内容插槽 -->
<slot name="content"></slot>
<!-- 底部插槽 -->
<slot name="footer"></slot>
</view>
-
- 父组件插入多插槽内容:通过 slot 属性指定插入的插槽,示例:
<my-component>
<view slot="header">这是头部内容</view>
<view slot="content">这是内容内容</view>
<view slot="footer">这是底部内容</view>
</my-component>
26. 小程序的组件样式隔离规则是什么?如何修改隔离规则?
解析:
- 默认样式隔离规则:小程序组件默认开启样式隔离,即:
-
- 组件的 WXSS 仅作用于组件内部,不会影响父组件或其他组件;
-
- 父组件的 WXSS 仅作用于父组件内部,不会影响组件内部;
-
- 全局样式(app.wxss)会作用于组件内部,但组件的局部样式优先级高于全局样式。
- 修改隔离规则:通过组件的 .js 中 options 节点的 styleIsolation 属性配置,可选值如下:
-
- "isolated"(默认):完全隔离,组件与父组件样式互不影响;
-
- "apply-shared":父组件样式影响组件内部,但组件样式不影响父组件;
-
- "shared":组件与父组件样式互相影响(不推荐,易导致样式污染);
-
- "scoped":类似 Vue 的 scoped,通过给组件节点添加唯一属性(如 data-weui-shadow)实现隔离(较少用)。
示例:
Component({
options: {
styleIsolation: "apply-shared" // 父组件样式影响组件内部
}
});
27. 小程序中如何获取自定义组件的实例?
解析:通过 this.selectComponent(选择器) 方法获取组件实例,可调用组件的方法或修改组件的 properties,步骤如下:
- 给组件添加选择器:在页面的 .wxml 中,给组件添加 id 或 class 选择器,示例:
<my-component id="myComponent" count="{{count}}"></my-component>
- 获取组件实例:在页面的 .js 中(需在页面 onReady 或组件 ready 后调用,确保组件已渲染),通过 this.selectComponent('#myComponent') 获取实例,示例:
Page({
onReady() {
// 获取组件实例
this.myComponent = this.selectComponent('#myComponent');
// 调用组件的方法(组件需在 methods 中定义该方法)
this.myComponent.handleComponentMethod();
// 修改组件的 properties(需通过 setData)
this.myComponent.setData({ count: 10 });
}
});
注意:① 选择器需符合 CSS 选择器规范(如 #id、.class);② 若组件在循环中(如 wx:for),需通过动态选择器(如 #myComponent-{{index}})获取。
28. 小程序的 behavior 是什么?它的作用是什么?如何使用?
解析:
- behavior 定义:behavior 是小程序的 “行为抽象”,用于提取多个组件的公共逻辑(如数据、方法、生命周期),实现逻辑复用(类似 Vue 的 mixin)。
- 作用:① 减少代码冗余,多个组件可共享同一套逻辑;② 便于维护,公共逻辑修改时仅需修改 behavior,无需修改所有组件。
- 使用步骤:
-
- 创建 behavior 文件:新建 .js 文件(如 my-behavior.js),用 Behavior 构造器定义,示例:
// my-behavior.js
module.exports = Behavior({
data: {
commonData: '这是公共数据'
},
properties: {
commonProp: String
},
methods: {
commonMethod() {
console.log('这是公共方法');
}
},
lifetimes: {
attached() {
console.log('behavior 的 attached 生命周期');
}
}
});
-
- 组件引入 behavior:在组件的 .js 中,通过 behaviors 数组引入 behavior,示例:
// 引入 behavior
const myBehavior = require('../../behaviors/my-behavior');
Component({
behaviors: [myBehavior], // 引入 behavior,可引入多个
attached() {
// 访问 behavior 的数据
console.log(this.data.commonData); // 这是公共数据
// 调用 behavior 的方法
this.commonMethod(); // 这是公共方法
}
});
- 优先级:若组件与 behavior 有同名数据 / 方法,组件的优先级高于 behavior;若多个 behavior 有同名数据 / 方法,后引入的 behavior 优先级高于先引入的。
29. 小程序的内置组件 scroll-view 有什么作用?使用时需要注意哪些问题?
解析:
- scroll-view 作用:用于实现局部滚动(如横向滚动列表、纵向滚动区域),可替代页面的全局滚动,支持自定义滚动触发事件(如滚动到底部、滚动到顶部)。
- 核心属性:
-
- scroll-x:是否允许横向滚动(true/false);
-
- scroll-y:是否允许纵向滚动(true/false);
-
- scroll-top/scroll-left:控制滚动条位置(需配合 setData 使用);
-
- bindscroll:滚动时触发,返回滚动距离(scrollTop/scrollLeft);
-
- bindscrolltolower:滚动到底部 / 右边时触发(类似上拉加载);
-
- bindscrolltoupper:滚动到顶部 / 左边时触发(类似下拉刷新)。
- 使用注意事项:
-
- 必须设置固定高度 / 宽度:纵向滚动(scroll-y=true)需给 scroll-view 设置固定高度(如 height: 500rpx),横向滚动(scroll-x=true)需设置固定宽度,否则无法滚动;
-
- 避免嵌套滚动:scroll-view 内部不建议再嵌套 scroll-view,可能导致滚动冲突;
-
- 性能优化:若滚动列表项较多,需配合 wx:key 提高渲染性能,避免频繁修改 scroll-top/scroll-left(可能导致卡顿);
-
- 与页面滚动冲突:若页面开启了全局滚动(默认开启),scroll-view 的滚动可能与页面滚动冲突,可通过 catchtouchmove 阻止页面滚动,示例:
<scroll-view scroll-y="true" style="height: 500rpx;" catchtouchmove="(e) => e.stopPropagation()">
<!-- 滚动内容 -->
</scroll-view>
30. 小程序的内置组件 swiper 有什么作用?如何实现自动轮播和无限轮播?
解析:
- swiper 作用:用于实现轮播图(如首页 Banner、图片轮播),内置指示器、切换动画,支持手势滑动。
- 核心子组件:
-
- <swiper-item>:轮播图的每一项,必须嵌套在 <swiper> 内,且仅能包含一个根节点;
-
- <indicator-dots>:是否显示轮播指示器(true/false)。
- 实现自动轮播:通过 autoplay 属性(是否自动切换,true/false)和 interval 属性(自动切换间隔时间,单位 ms,默认 5000)实现,示例:
<swiper autoplay="true" interval="3000" indicator-dots="true">
<swiper-item><image src="/images/banner1.jpg" mode="widthFix"></image></swiper-item>
<swiper-item><image src="/images/banner2.jpg" mode="widthFix"></image></swiper-item>
<swiper-item><image src="/images/banner3.jpg" mode="widthFix"></image></swiper-item>
</swiper>
- 实现无限轮播:小程序的 swiper 默认支持无限轮播,无需额外配置;若需自定义轮播逻辑(如手动控制),可通过 current 属性(当前轮播索引)和 bindchange 事件(轮播切换时触发)实现,示例:
Page({
data: {
current: 0,
bannerList: [1, 2, 3] // 轮播数据
},
handleSwiperChange(e) {
this.setData({ current: e.detail.current });
},
// 手动切换到下一张
nextBanner() {
const { current, bannerList } = this.data;
const nextIndex = current === bannerList.length - 1 ? 0 : current + 1;
this.setData({ current: nextIndex });
}
});
- 注意事项:① <swiper-item> 内的图片建议设置 mode="widthFix" 保持宽高比;② 轮播图数量较少时(如 1 张),建议关闭自动轮播(autoplay="false"),避免不必要的切换。
四、API 与数据存储(31-40 题)
31. 小程序的网络请求 API wx.request 有什么作用?使用时需要注意哪些问题?
解析:
- wx.request 作用:用于发起 HTTP/HTTPS 请求(类似 H5 的 fetch 或 axios),获取后端数据,支持 GET、POST 等请求方法。
- 基础用法:
wx.request({
url: 'https://api.example.com/getList', // 接口地址(必须是 HTTPS,且已在微信公众平台配置域名)
method: 'GET', // 请求方法(GET/POST/PUT/DELETE,默认 GET)
data: { page: 1, pageSize: 10 }, // 请求参数(GET 会拼到 URL,POST 会放在请求体)
header: { 'content-type': 'application/json' }, // 请求头(POST 需设置为 'application/x-www-form-urlencoded' 时,参数需转成表单格式)
success(res) {
console.log('请求成功', res.data); // res.data 为后端返回的响应数据
},
fail(err) {
console.log('请求失败', err); // 请求错误(如网络异常、域名未配置)
},
complete() {
console.log('请求完成(无论成功/失败都会触发)');
}
});
- 使用注意事项:
-
- 域名配置:请求的 URL 必须是 HTTPS 协议,且域名需在微信公众平台 “开发 → 开发设置 → 服务器域名” 中配置(测试环境可使用 “微信开发者工具 → 详情 → 本地设置 → 不校验合法域名” 规避);
-
- 请求限制:同一域名下的并发请求数不超过 10 个;
-
- 超时时间:可在 app.json 中配置 networkTimeout(默认 60000ms),超时后会触发 fail 回调;
-
- POST 请求参数格式:若后端需要表单格式(application/x-www-form-urlencoded),需将 data 转成 key=value&key=value 格式(可使用 qs.stringify(data));
-
- 错误处理:需处理网络异常、接口返回错误码等情况,避免页面卡住。
32. 小程序的本地存储 API 有哪些?它们的区别是什么?存储限制是什么?
解析:
- 本地存储 API 分类:分为同步 API 和异步 API,共 4 个:
-
- wx.setStorageSync(key, data):同步存储数据(阻塞当前线程,适合简单场景);
-
- wx.getStorageSync(key):同步获取数据;
-
- wx.setStorage({ key, data, success, fail }):异步存储数据(非阻塞,适合复杂场景,需通过回调处理结果);
-
- wx.getStorage({ key, success, fail }):异步获取数据;
此外,还有 wx.removeStorage/wx.removeStorageSync(删除指定 key 的数据)、wx.clearStorage/wx.clearStorageSync(清空所有本地存储)。
- 同步与异步的区别:
维度 |
同步 API(Sync 后缀) |
异步 API(无 Sync 后缀) |
执行方式 |
阻塞当前线程,执行完成后再继续后续代码 |
非阻塞,代码继续执行,结果通过回调返回 |
错误处理 |
需用 try-catch 捕获错误 |
错误通过 fail 回调返回 |
使用场景 |
简单数据存储 / 获取(如初始化数据) |
大量数据存储 / 获取(避免阻塞线程) |
- 存储限制:
-
- 单个 key 的数据大小不超过 1MB;
-
- 所有 key 的总存储量不超过 10MB;
-
- 存储的数据类型仅支持:String、Number、Boolean、Object、Array(复杂对象会被转成 JSON 字符串存储,获取时需解析)。
- 示例(同步存储 / 获取):
// 存储数据
try {
wx.setStorageSync('userInfo', { name: '张三', age: 20 });
} catch (e) {
console.log('存储失败', e);
}
// 获取数据
try {
const userInfo = wx.getStorageSync('userInfo');
console.log(userInfo); // { name: '张三', age: 20 }
} catch (e) {
console.log('获取失败', e);
}
33. 小程序如何获取用户信息?新旧接口有什么区别?
解析:小程序获取用户信息的接口经历过调整,目前主要使用 wx.getUserProfile(推荐)和 wx.getUserInfo(旧接口,限制较多):
- 旧接口:wx.getUserInfo:
-
- 作用:获取用户的昵称、头像、性别等信息,但 需用户已授权 scope.userInfo;
-
- 限制:① 若用户未授权,调用该接口会直接进入 fail 回调,无法主动触发授权弹窗;② 自 2022 年 10 月起,新提交的小程序无法再通过该接口获取用户信息(需用新接口);
-
- 示例:
wx.getUserInfo({
success(res) {
console.log('用户信息', res.userInfo); // { nickName: '张三', avatarUrl: 'xxx', ... }
},
fail(err) {
console.log('未授权', err);
}
});
- 新接口:wx.getUserProfile:
-
- 作用:替代 wx.getUserInfo,支持主动触发授权弹窗,获取用户信息;
-
- 优势:① 无需提前授权,调用时会弹出授权弹窗(用户可选择允许 / 拒绝);② 支持获取 encryptedData(加密数据,需后端解密获取 unionId 等敏感信息);
-
- 限制:① 必须在 用户点击事件 中调用(如 bindtap,避免自动触发);② 每次调用都会触发授权弹窗(用户可选择不再授权);
-
- 示例:
// WXML:<button bindtap="getUserProfile">获取用户信息</button>
Page({
getUserProfile(e) {
wx.getUserProfile({
desc: '用于完善会员资料', // 必传,说明获取信息的用途(会显示在授权弹窗中)
success(res) {
console.log('用户信息', res.userInfo); // { nickName: '张三', avatarUrl: 'xxx', ... }
// 存储用户信息到本地
wx.setStorageSync('userInfo', res.userInfo);
},
fail(err) {
console.log('用户拒绝授权', err);
}
});
}
});
- 核心区别:新接口 wx.getUserProfile 可主动触发授权弹窗,旧接口 wx.getUserInfo 依赖提前授权,且新接口是目前官方推荐的方式。
34. 小程序的登录流程是什么?如何获取用户的 openId 和 unionId?
解析:小程序登录的核心是通过微信生态获取用户的唯一标识(openId/unionId),实现用户身份认证,流程如下:
- 获取临时登录凭证 code:调用 wx.login() 获取 code(有效期 5 分钟,仅能使用 1 次);
- code 换 sessionKey 和 openId:将 code 发送到开发者服务器,服务器调用微信开放平台的 code2Session 接口(https://api.weixin.qq.com/sns/jscode2session),获取 sessionKey(会话密钥)、openId(用户在当前小程序的唯一标识);
- 生成自定义登录态:服务器根据 openId 和 sessionKey 生成自定义登录态(如 Token),返回给小程序;
- 存储登录态:小程序将 Token 存储到本地(如 wx.setStorageSync('token', token)),后续请求接口时在 header 中携带 Token,实现身份验证。
- 获取 openId:通过 code2Session 接口直接返回,无需额外操作,示例(服务器端代码,以 Node.js 为例):
const request = require('request');
const appId = '你的小程序 AppID';
const appSecret = '你的小程序 AppSecret';
function code2Session(code) {
return new Promise((resolve, reject) => {
const url = `https://api.weixin.qq.com/sns/jscode2session?appid=${appId}&secret=${appSecret}&js_code=${code}&grant_type=authorization_code`;
request.get(url, (err, res, body) => {
if (err) reject(err);
const data = JSON.parse(body);
// data 包含 openid、session_key、expires_in
resolve(data);
});
});
}
- 获取 unionId:unionId 是用户在微信开放平台下所有应用(小程序、公众号、App)的唯一标识,需满足以下条件之一:
-
- 小程序已关联到微信开放平台账号(“微信开放平台 → 管理中心 → 关联小程序”);
-
- 用户已授权 wx.getUserProfile,服务器通过 encryptedData(wx.getUserProfile 返回的加密数据)和 sessionKey 解密,获取 unionId(需使用微信提供的解密算法)。
35. 小程序如何调用微信支付?核心流程是什么?
解析:小程序调用微信支付需结合微信支付商户平台和开发者服务器,核心流程如下(需已开通微信支付功能):
- 用户发起支付请求:用户在小程序中点击支付按钮,小程序将订单信息(如订单号、金额)发送到开发者服务器;
- 服务器生成预支付订单:开发者服务器调用微信支付的 统一下单接口(https://api.mch.weixin.qq.com/pay/unifiedorder),传入商户号、AppID、订单信息等参数,获取 prepay_id(预支付订单号);
- 服务器生成支付参数:服务器根据 prepay_id、商户号等参数,按照微信支付的签名规则生成 paySign(支付签名),并将 appId、timeStamp、nonceStr、package(格式为 prepay_id=xxx)、signType(签名类型,如 MD5)、paySign 等参数返回给小程序;
- 小程序调起支付:小程序调用 wx.requestPayment 接口,传入服务器返回的支付参数,调起微信支付弹窗;
- 支付结果通知:用户支付完成后,微信服务器会向开发者服务器的 notify_url(统一下单时指定)发送支付结果通知,服务器需验证通知的签名,并更新订单状态;
- 小程序处理支付结果:wx.requestPayment 的 success/fail/complete 回调会返回支付结果(但最终订单状态需以服务器收到的微信通知为准,避免前端伪造结果)。
- 小程序端核心代码:
// 调用服务器接口获取支付参数
getPayParams(orderId).then(payParams => {
// 调起微信支付
wx.requestPayment({
timeStamp: payParams.timeStamp + '', // 必须是字符串
nonceStr: payParams.nonceStr,
package: payParams.package,
signType: payParams.signType,
paySign: payParams.paySign,
success(res) {
console.log('支付成功', res);
// 跳转支付成功页面
wx.navigateTo({ url: '/pages/paySuccess/paySuccess' });
},
fail(err) {
console.log('支付失败', err);
wx.showToast({ title: '支付失败', icon: 'none' });
}
});
});
- 注意事项:① 订单金额单位是 “分”(如 1 元需传 100);② 签名必须严格按照微信支付的规则生成,否则会调起失败;③ 必须处理支付结果通知(异步通知),避免漏单。
36. 小程序如何实现分享功能?支持哪些分享方式?
解析:小程序支持 “页面内分享” 和 “右上角菜单分享”,需通过生命周期和 API 配置:
- 页面内分享(按钮分享):通过 <button> 组件的 open-type="share" 实现,点击按钮触发分享弹窗,示例:
-
- WXML:<button open-type="share">分享给好友</button>;
-
- 自定义分享内容:在页面的 .js 中实现 onShareAppMessage 生命周期,返回分享标题、路径、图片,示例:
onShareAppMessage(res) {
// res.from 可判断分享来源(button:按钮分享,menu:右上角菜单分享)
return {
title: '这是分享标题', // 分享标题(默认是小程序名称)
path: '/pages/index/index?shareId=123', // 分享路径(必须是当前小程序的页面,可携带参数)
imageUrl: '/images/share.jpg' // 分享图片(建议尺寸 5:4,默认是页面截图)
};
}
- 右上角菜单分享(转发给好友):无需额外按钮,用户点击微信右上角 “...” → “转发” 即可触发,分享内容同样通过 onShareAppMessage 配置。
- 分享到朋友圈:通过 onShareTimeline 生命周期实现(仅支持微信 7.0.12 及以上版本),示例:
onShareTimeline() {
return {
title: '这是朋友圈分享标题',
query: 'shareId=123', // 分享路径参数(对应 path 中的查询字符串)
imageUrl: '/images/share.jpg'
};
}
- 注意事项:① 分享路径必须是小程序的已注册页面(在 app.json 的 pages 中定义);② 分享参数需在目标页面的 onLoad 中通过 options 获取;③ 禁止分享的页面可在页面的 .json 中设置 "disableShareAppMessage": true(禁止转发给好友)或 "disableShareTimeline": true(禁止分享到朋友圈)。
37. 小程序如何获取设备信息?常用的设备信息有哪些?
解析:通过 wx.getSystemInfo 或 wx.getSystemInfoSync 获取设备信息,前者是异步 API,后者是同步 API:
- 基础用法(同步 API,常用):
try {
const systemInfo = wx.getSystemInfoSync();
console.log(systemInfo);
} catch (e) {
console.log('获取设备信息失败', e);
}
- 常用设备信息字段:
-
- model:设备型号(如 iPhone 13、MI 11);
-
- system:操作系统版本(如 iOS 15.4、Android 12);
-
- pixelRatio:设备像素比(如 2、3,用于计算图片尺寸);
-
- screenWidth/screenHeight:屏幕宽度 / 高度(单位 px);
-
- windowWidth/windowHeight:可使用窗口宽度 / 高度(不含导航栏、状态栏,单位 px);
-
- statusBarHeight:状态栏高度(单位 px,用于自定义导航栏适配);
-
- platform:设备平台(ios/android/devtools,用于处理平台差异);
-
- version:微信版本号(如 7.0.20,用于判断 API 兼容性)。
- 应用场景:① 适配不同设备的屏幕尺寸(如根据 windowWidth 计算组件宽度);② 处理 iOS 和 Android 的差异(如时间格式、滚动行为);③ 自定义导航栏时,根据 statusBarHeight 计算导航栏高度。
38. 小程序如何实现图片预览功能?
解析:通过 wx.previewImage API 实现图片预览,支持手势缩放、左右滑动切换图片,步骤如下:
- 页面结构(WXML):展示图片列表,给每张图片绑定点击事件,传递当前图片索引,示例:
<view class="image-list">
<image
wx:for="{{imageList}}"
wx:key="index"
src="{{item}}"
mode="widthFix"
bindtap="handlePreviewImage"
data-index="{{index}}"
></image>
</view>
- 逻辑实现(JS):在点击事件中调用 wx.previewImage,传入当前图片 URL 和所有图片 URL 列表,示例:
Page({
data: {
imageList: [
'https://example.com/image1.jpg',
'https://example.com/image2.jpg',
'https://example.com/image3.jpg'
]
},
handlePreviewImage(e) {
const index = e.currentTarget.dataset.index;
const currentImage = this.data.imageList[index];
// 调用图片预览 API
wx.previewImage({
current: currentImage, // 当前预览的图片 URL
urls: this.data.imageList // 所有可预览的图片 URL 列表(必须是数组)
});
}
});
- 注意事项:① urls 参数必须是数组,且数组中的 URL 必须是有效的图片地址(支持 HTTP/HTTPS);② 预览的图片支持 JPG、PNG、GIF 等格式;③ 若图片是本地临时文件(如相机拍摄的图片),需传入临时文件路径(如 wx.chooseImage 返回的 tempFilePaths)。
39. 小程序如何实现拍照或选择相册图片功能?
解析:通过 wx.chooseImage API 实现,支持从相册选择图片或调用相机拍照,步骤如下:
- 页面结构(WXML):添加按钮触发选择图片事件,展示已选择的图片,示例:
<button bindtap="chooseImage">选择图片(拍照/相册)</button>
<view class="image-list">
<image
wx:for="{{selectedImages}}"
wx:key="index"
src="{{item}}"
mode="widthFix"
bindtap="previewImage"
data-index="{{index}}"
></image>
</view>
- 逻辑实现(JS):调用 wx.chooseImage,配置选择来源(相册 / 相机)、最多选择数量等参数,示例:
Page({
data: {
selectedImages: [] // 已选择的图片列表(临时文件路径)
},
chooseImage() {
wx.chooseImage({
count: 3, // 最多选择 3 张图片
sizeType: ['original', 'compressed'], // 可选择原图或压缩图
sourceType: ['album', 'camera'], // 可选择相册或相机(默认两者都有)
success(res) {
// res.tempFilePaths 是选择的图片临时文件路径列表(本地路径,有效期至小程序退出)
const newImages = this.data.selectedImages.concat(res.tempFilePaths);
this.setData({ selectedImages: newImages });
}
});
},
// 预览已选择的图片
previewImage(e) {
const index = e.currentTarget.dataset.index;
wx.previewImage({
current: this.data.selectedImages[index],
urls: this.data.selectedImages
});
}
});
- 注意事项:① tempFilePaths 是临时路径,若需长期保存,需调用 wx.uploadFile 上传到服务器;② 若仅允许相机拍照,可设置 sourceType: ['camera'];③ 选择的图片大小有限制(默认不超过 10MB,可通过 sizeType 选择压缩图减少大小)。
40. 小程序的 wx.uploadFile API 有什么作用?如何使用它上传图片或文件?
解析:
- wx.uploadFile 作用:用于将本地文件(如图片、文档)上传到开发者服务器,支持进度监听,常用于上传头像、表单附件等场景。
- 核心参数:
-
- url:服务器上传接口地址(必须是 HTTPS,且已配置域名);
-
- filePath:本地文件路径(如 wx.chooseImage 返回的 tempFilePaths 中的路径);
-
- name:文件对应的 key(需与服务器接口约定,如 file);
-
- formData:额外的表单参数(如用户 ID、文件类型);
-
- success:上传成功回调,返回服务器响应数据;
-
- fail:上传失败回调;
-
- progress:上传进度回调,返回 progress(进度百分比)、totalBytesSent(已上传字节数)、totalBytesExpectedToSend(预期总字节数)。
- 上传图片示例:
// 1. 先选择图片
wx.chooseImage({
count: 1,
sourceType: ['album', 'camera'],
success(chooseRes) {
const filePath = chooseRes.tempFilePaths[0]; // 选中的图片临时路径
// 2. 上传图片到服务器
wx.uploadFile({
url: 'https://api.example.com/uploadImage', // 服务器上传接口
filePath: filePath,
name: 'file', // 服务器接收文件的 key
formData: {
userId: '123', // 额外参数:用户 ID
fileType: 'image' // 额外参数:文件类型
},
// 监听上传进度
progress(res) {
console.log('上传进度:', res.progress + '%');
},
success(uploadRes) {
// 服务器返回的响应数据(默认是字符串,需转成 JSON)
const data = JSON.parse(uploadRes.data);
if (data.code === 200) {
console.log('上传成功,图片 URL:', data.data.imageUrl);
// 存储图片 URL 到本地或页面数据
}
},
fail(err) {
console.log('上传失败', err);
wx.showToast({ title: '上传失败', icon: 'none' });
}
});
}
});
- 注意事项:① 服务器接口需支持 multipart/form-data 格式(文件上传的标准格式);② 若上传大文件(如超过 5MB),需确保服务器配置了足够的超时时间;③ 上传成功后,服务器需返回文件的访问 URL(如 CDN 地址),小程序后续可通过该 URL 访问文件。
更多推荐
所有评论(0)