小程序作为一种“用完即走、无需安装”的轻应用凭借微信、支付宝等超级App的流量生态已成为前端开发者的必备技能。无论你打算开发一个电商工具、信息展示页还是复杂的互动社区理解其基础代码结构都是第一步。本文以微信小程序为例从项目文件结构、页面组成、数据绑定、事件响应到常见 API 调用手把手带你写出一个可运行的小程序核心模块。代码基于微信小程序基础库 3.x兼容绝大多数真机与开发者工具。一、小程序项目的最小构成一个最简单的微信小程序至少包含以下文件text复制下载my-app/ ├── app.js # 全局逻辑 ├── app.json # 全局配置导航栏、窗口样式、页面路径等 ├── app.wxss # 全局样式可选 └── pages/ └── index/ ├── index.js # 页面逻辑 ├── index.wxml # 页面结构类似HTML ├── index.wxss # 页面样式 └── index.json # 页面配置可选1.1 全局配置app.json所有小程序都必须包含app.json它告诉微信小程序框架项目中有哪些页面、窗口外观如何json复制下载{ pages: [ pages/index/index, pages/logs/logs ], window: { navigationBarBackgroundColor: #1677ff, navigationBarTitleText: 我的小程序, navigationBarTextStyle: white, backgroundColor: #f8f8f8 }, tabBar: { list: [ { pagePath: pages/index/index, text: 首页, iconPath: images/home.png, selectedIconPath: images/home_active.png }, { pagePath: pages/logs/logs, text: 日志, iconPath: images/log.png, selectedIconPath: images/log_active.png } ] }, style: v2, sitemapLocation: sitemap.json }pages数组第一项为启动页面。window定义所有页面的默认导航栏、背景色等。tabBar用于底部导航栏至少两项最多五项。1.2 全局逻辑app.jsApp()函数注册小程序实例可定义全局数据与生命周期javascript复制下载// app.js App({ onLaunch(options) { // 小程序启动时执行 console.log(App launched, options); }, globalData: { userInfo: null, apiBase: https://api.example.com } });其他页面可通过getApp()访问这些全局数据。二、页面的四大组成文件以首页pages/index/index为例四个文件协同工作。2.1 页面结构.wxml—— 相当于 HTMLWXML 提供了数据绑定、条件渲染、循环等能力xml复制下载运行!--pages/index/index.wxml-- view classcontainer !-- 数据绑定{{ }} -- text classtitle{{title}}/text !-- 条件渲染 -- view wx:if{{showTip}} classtip温馨提示点击按钮获取数据/view !-- 列表渲染 -- view wx:for{{items}} wx:keyindex classitem text{{index 1}}. {{item.name}}/text /view !-- 事件绑定bindtap -- button typeprimary bindtaponFetchData请求数据/button !-- 展示网络返回结果 -- view wx:if{{responseData}} classresponse text{{responseData}}/text /view /view常用组件view容器、text文本、button、image、input、scroll-view等。2.2 页面样式.wxss—— 扩展的 CSSWXSS 基本支持 CSS 全部特性并加入rpx响应式像素单位css复制下载/* pages/index/index.wxss */ .container { padding: 40rpx; /* rpx 可根据屏幕宽度自适应1rpx 屏幕宽/750 */ background-color: #f5f5f5; min-height: 100vh; } .title { font-size: 36rpx; font-weight: bold; color: #1677ff; display: block; margin-bottom: 30rpx; } .item { background: white; padding: 20rpx; margin-bottom: 20rpx; border-radius: 16rpx; box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.05); } .tip { color: #ff6600; font-size: 28rpx; margin: 20rpx 0; } .response { margin-top: 30rpx; background: #eef2ff; padding: 20rpx; border-radius: 12rpx; word-break: break-all; }注意小程序不支持通配符*选择器且部分伪类如:hover只对特定组件生效。2.3 页面逻辑.js—— Page 对象Page()函数定义页面数据、生命周期、事件处理函数javascript复制下载// pages/index/index.js Page({ data: { title: 小程序开发示例, showTip: true, items: [ { name: 苹果 }, { name: 香蕉 }, { name: 橙子 } ], responseData: }, onLoad(options) { // 页面加载时触发options 为跳转参数 console.log(页面加载, options); // 可以在这里发起初始请求 this.loadInitialData(); }, onShow() { // 页面显示时触发包括从后台切回 console.log(页面显示); }, loadInitialData() { // 模拟本地数据展示 this.setData({ showTip: false }); }, // 事件处理获取网络数据 onFetchData() { const that this; wx.showLoading({ title: 加载中... }); wx.request({ url: https://jsonplaceholder.typicode.com/posts/1, method: GET, success(res) { wx.hideLoading(); if (res.statusCode 200) { that.setData({ responseData: JSON.stringify(res.data, null, 2) }); } else { wx.showToast({ title: 请求失败, icon: none }); } }, fail(err) { wx.hideLoading(); wx.showToast({ title: 网络错误, icon: error }); console.error(err); } }); } });核心概念this.setData()是更新界面和数据的唯一方法直接修改this.data不会触发视图更新。小程序不支持 Vue 中的双向绑定需手动监听input事件并setData。2.4 页面配置.json—— 覆盖全局设置若某个页面需要独立配置导航栏或下拉刷新可在同名的.json中声明json复制下载{ usingComponents: {}, navigationBarTitleText: 首页 - 定制标题, enablePullDownRefresh: true, backgroundColor: #eeeeee }三、数据绑定与事件响应的深入细节3.1 数据绑定语法WXML 中用双大括号{{ }}包裹变量支持简单运算xml复制下载运行view计算{{a b}}/view view三元{{gender 1 ? 男 : 女}}/view view hidden{{flag ? true : false}}条件隐藏/view注意不能在花括号内调用函数或定义复杂对象应在Page.data中预先处理。3.2 条件与循环wx:if/wx:elif/wx:else惰性渲染适合切换频率低的情况。hidden组件始终渲染仅控制显示隐藏适合高频切换。wx:for循环数组必须指定wx:key以提升重渲染性能可用*this或唯一字段。xml复制下载运行view wx:for{{users}} wx:keyid 姓名{{item.name}}年龄{{item.age}} /view3.3 事件绑定与传参常用事件bindtap点击、bindinput输入、bindconfirm确认。传递自定义参数使用data-*属性然后在事件对象的currentTarget.dataset中获取。xml复制下载运行button bindtaponDelete data-id{{item.id}} data-name{{item.name}}删除/buttonjavascript复制下载onDelete(e) { const { id, name } e.currentTarget.dataset; console.log(删除 id${id}, name${name}); // 执行删除逻辑 }表单输入双向模拟xml复制下载运行input placeholder请输入用户名 bindinputonInputUserName value{{userName}}/javascript复制下载data: { userName: }, onInputUserName(e) { this.setData({ userName: e.detail.value }); }四、常用 API 速览基础代码必备4.1 网络请求wx.request类似浏览器fetch但需配置合法域名在微信公众平台后台设置 request 域名。javascript复制下载wx.request({ url: https://api.com/data, method: POST, data: { key: value }, header: { content-type: application/json }, success(res) { /* 处理成功 */ }, fail(err) { /* 处理失败 */ } });4.2 本地存储wx.setStorageSync/wx.getStorageSync同步 API 更适合简单场景javascript复制下载// 存储 wx.setStorageSync(token, abc123); // 读取 const token wx.getStorageSync(token); // 删除 wx.removeStorageSync(token);异步版本wx.setStorage不会阻塞 UI适合大数据。4.3 界面交互wx.showToast轻提示wx.showModal确认对话框wx.showLoading/wx.hideLoadingwx.showActionSheet底部操作菜单javascript复制下载wx.showModal({ title: 提示, content: 确定要删除吗, success(res) { if (res.confirm) { // 确认操作 } } });4.4 页面跳转javascript复制下载// 保留当前页面跳转到新页面可返回 wx.navigateTo({ url: /pages/detail/detail?id123 }); // 关闭当前页面跳转到新页面 wx.redirectTo({ url: /pages/login/login }); // 切换到 tabBar 页面 wx.switchTab({ url: /pages/index/index }); // 返回上一页 wx.navigateBack({ delta: 1 });页面间传参通过 URL query 字符串在目标页面的onLoad(options)中获取。五、一个完整的交互示例待办清单Todo核心代码为了巩固上述知识点下面实现一个简单的待办清单页面。index.wxmlxml复制下载运行view classtodo-container view classinput-row input placeholder输入新任务 bindinputonInput value{{newTodo}} / button typeprimary sizemini bindtapaddTodo添加/button /view view wx:for{{todos}} wx:keyid classtodo-item checkbox value{{item.id}} checked{{item.completed}} bindtaptoggleTodo data-id{{item.id}}/ text class{{item.completed ? completed : }}{{item.text}}/text button sizemini typewarn bindtapdeleteTodo data-id{{item.id}}删除/button /view view classstats共 {{todos.length}} 项已完成 {{completedCount}} 项/view /viewindex.jsjavascript复制下载Page({ data: { newTodo: , todos: [], completedCount: 0 }, onLoad() { // 从本地存储加载数据 const stored wx.getStorageSync(todos); if (stored) { this.setData({ todos: stored }); this.updateCompletedCount(); } }, onInput(e) { this.setData({ newTodo: e.detail.value }); }, addTodo() { if (!this.data.newTodo.trim()) return; const newItem { id: Date.now(), text: this.data.newTodo, completed: false }; const newTodos [...this.data.todos, newItem]; this.setData({ todos: newTodos, newTodo: }); this.updateCompletedCount(); wx.setStorageSync(todos, newTodos); }, toggleTodo(e) { const id e.currentTarget.dataset.id; const todos this.data.todos.map(item { if (item.id id) item.completed !item.completed; return item; }); this.setData({ todos }); this.updateCompletedCount(); wx.setStorageSync(todos, todos); }, deleteTodo(e) { const id e.currentTarget.dataset.id; const todos this.data.todos.filter(item item.id ! id); this.setData({ todos }); this.updateCompletedCount(); wx.setStorageSync(todos, todos); }, updateCompletedCount() { const count this.data.todos.filter(item item.completed).length; this.setData({ completedCount: count }); } });index.wxss略但你已经掌握了基础样式写法。六、常见错误与排坑指南setData 的数据量过大避免一次性传递大量数据例如超长数组可考虑分页加载。单次setData的数据大小建议不超过 1MB。this 指向丢失在异步回调或嵌套函数中提前用const that this保存或使用箭头函数。页面路径大小写敏感app.json中的路径必须与实际文件路径完全一致包括大小写否则开发者工具不会报错但真机无法加载。请求域名未配置开发阶段可在开发者工具中勾选“不校验合法域名”但正式上线前务必在后台配置。不支持 DOM 操作小程序无法通过document或window访问节点。若需获取元素宽高使用wx.createSelectorQuery()。结语小程序的“基础代码”并不复杂——它本质上是经过封装的MVVM 框架WXML 提供视图模板JS 管理数据与逻辑WXSS 负责样式。掌握上述.wxml、.js、.wxss、.json四件套理解setData和生命周期便已经跨过了最核心的门槛。建议你立即打开微信开发者工具创建一个空白项目亲手把待办清单的例子敲一遍并尝试增加“编辑任务”或“清空已完成”等功能。不断迭代这些小模块小程序开发能力就会快速成长。