1. 引言
随着微信小程序业务逻辑日益复杂,把所有代码堆在单个index.js文件里会导致代码臃肿、难以维护。模块化开发是提升代码可读性、可复用性和可测试性的关键手段。本文将通过实战案例,详细介绍如何在index.js中引用不同模块的变量和函数,帮助你快速掌握小程序模块化开发的核心技巧。
2. 模块化开发基础
微信小程序基于 CommonJS 规范实现模块化。每个.js文件都是一个独立模块,模块内部定义的变量和函数默认对外不可见,需要通过module.exports或exports导出,其他文件才能通过require引入使用。
在动手编码之前,先明确两个核心概念:
- 导出(Export):模块通过
module.exports暴露需要共享的变量和函数。 - 引入(Require):其他文件通过
require('模块路径')获取导出的内容。
3. 项目结构规划
合理的目录结构是模块化开发的第一步。下面是一个推荐的工程结构:
miniprogram/ ├── app.js ├── app.json ├── pages/ │ └── index/ │ ├── index.js │ ├── index.wxml │ ├── index.wxss │ └── index.json ├── utils/ │ ├── format.js │ ├── request.js │ └── constants.js └── services/ └── user.js其中utils目录存放通用工具模块,services目录存放业务逻辑模块,pages/index/index.js作为页面入口负责组合调用这些模块。
4. 创建可复用的工具模块
我们先创建两个基础工具模块,分别负责常量管理和格式化处理。
4.1 定义常量模块
创建utils/constants.js,集中管理全局配置和枚举值:
// utils/constants.js const APP_NAME = '小程序实战'; const API_BASE_URL = 'https://api.example.com'; const HTTP_STATUS = { SUCCESS: 200, NOT_FOUND: 404, SERVER_ERROR: 500 }; module.exports = { APP_NAME, API_BASE_URL, HTTP_STATUS };4.2 定义格式化模块
创建utils/format.js,封装日期和数字格式化函数:
// utils/format.js function formatDate(date, separator = '-') { const y = date.getFullYear(); const m = String(date.getMonth() + 1).padStart(2, '0'); const d = String(date.getDate()).padStart(2, '0'); return `${y}${separator}${m}${separator}${d}`; } function formatPrice(price) { return `¥${Number(price).toFixed(2)}`; } module.exports = { formatDate, formatPrice };5. 创建业务逻辑模块
接下来创建一个用户服务模块,模拟用户登录和资料获取逻辑。
创建services/user.js,该模块会引用上面定义的常量模块:
// services/user.js const { API_BASE_URL, HTTP_STATUS } = require('../utils/constants.js'); async function login(username, password) { try { const response = await wx.request({ url: `${API_BASE_URL}/login`, method: 'POST', data: { username, password } }); if (response.statusCode === HTTP_STATUS.SUCCESS) { return response.data; } throw new Error('登录失败'); } catch (error) { console.error('登录异常:', error); return null; } } async function getUserInfo(userId) { // 模拟获取用户信息 return { id: userId, name: '张三', level: 'VIP' }; } module.exports = { login, getUserInfo };6. 在 index.js 中引用多个模块
现在进入核心环节:在页面入口pages/index/index.js中同时引用上述多个模块的变量和函数。
6.1 引入模块
使用require引入常量、格式化和用户服务模块:
// pages/index/index.js const { APP_NAME, HTTP_STATUS } = require('../../utils/constants.js'); const { formatDate, formatPrice } = require('../../utils/format.js'); const { login, getUserInfo } = require('../../services/user.js');6.2 使用模块中的变量和函数
在Page配置中组合使用这些模块能力:
Page({ data: { appName: APP_NAME, today: '', price: '', userInfo: null }, onLoad() { this.setData({ today: formatDate(new Date()), price: formatPrice(19.9) }); this.fetchUserInfo(); }, async fetchUserInfo() { const userInfo = await getUserInfo(1001); this.setData({ userInfo }); }, async handleLogin() { const result = await login('admin', '123456'); if (result) { wx.showToast({ title: '登录成功' }); } } });通过上述代码可以看到,index.js通过解构赋值分别从三个模块中引用了变量APP_NAME、HTTP_STATUS和函数formatDate、formatPrice、login、getUserInfo,实现了逻辑的清晰分层。
7. 模块化开发最佳实践
为了让模块化开发更高效、更健壮,这里总结几条实战经验:
- 单一职责:每个模块只负责一类能力,例如常量、请求、格式化各自独立成文件。
- 相对路径规范:统一使用相对路径引入模块,避免绝对路径在迁移时失效。
- 按需解构:引入时只解构当前文件需要的变量和函数,减少内存占用和命名冲突。
- 循环引用规避:避免 A 模块 require B 模块、B 模块又 require A 模块,防止初始化顺序异常。
- 统一出口:对于复杂业务域,可以在目录下增加
index.js统一导出,简化外部引用路径。
8. 常见问题与排查
模块化开发中经常遇到两类问题,这里给出排查思路。
8.1 模块找不到
如果报错module not found,优先检查require路径是否正确,尤其是层级关系。建议从当前文件出发逐级核对../数量。
8.2 导出的值为空
如果引入后拿到undefined,多半是导出语句写错。检查是否遗漏module.exports,或者导出对象中的键名与解构名称不一致。
9. 总结
本文通过一个完整的实战案例,演示了微信小程序中如何通过module.exports导出变量和函数,并在index.js中通过require引用不同模块。模块化开发不仅能显著降低代码耦合度,还能提升团队协作效率和代码可维护性。建议你在实际项目中从小工具模块开始实践,逐步将业务逻辑拆分为独立服务模块,形成清晰、可复用的工程结构。