0%

一步步从0开发一个微信小程序

微信小程序以其轻量、便捷、跨平台的特性,成为了连接线上线下的重要工具。本教程将根据微信小程序最新的开发文档,从零开始,一步步开发一个功能完整的 “待办事项 (Todo List)” 小程序。

目标功能

我们将开发的Todo List小程序将具备以下功能:

  1. 添加待办事项:用户可以在输入框中输入新的待办事项并添加。
  2. 显示待办事项列表:所有待办事项以列表形式展示。
  3. 标记完成/未完成:每个事项可以被标记为已完成或未完成。
  4. 删除待办事项:可以从列表中删除某个事项。
  5. 数据持久化:关闭小程序后,数据不会丢失(使用本地存储)。

准备工作

在开始开发之前,需要准备以下工具和账号:

  1. 微信开发者账号 (个人或企业)

    • 访问 微信公众平台
    • 注册一个服务号、订阅号、小程序或企业微信,并选择注册小程序。(这一步注意小程序与公众号的区别,一定是小程序,且注册了公众号的邮箱不能用作小程序的注册)
    • 注册成功后,登录后台,在 “开发” -> “开发设置” 中获取您的 AppID(小程序ID)。这个ID在开发和发布小程序时非常重要。
  2. 微信开发者工具

  3. 基础前端知识

    • 熟悉 HTML、CSS、JavaScript 基本语法。
    • 理解数据绑定和事件处理等概念。

核心概念回顾

在深入开发之前,我们先简单回顾一下小程序的核心文件类型和作用:

  • 项目目录/app.js: 小程序逻辑文件。注册小程序应用,监听生命周期,声明全局变量等。
  • 项目目录/app.json: 小程序全局配置文件。配置所有页面路径、窗口表现、网络超时、底部 TabBar 等。
  • 项目目录/app.wxss: 小程序全局样式文件。类似于 CSS,作用于所有页面。
  • 项目目录/pages/页面名/页面名.js: 页面逻辑文件。注册页面,声明数据、生命周期、事件处理函数等。
  • 项目目录/pages/页面名/页面名.json: 页面配置文件。配置当前页面的窗口表现。优先级高于 app.json
  • 项目目录/pages/页面名/页面名.wxml: 页面结构文件。类似 HTML,用于描述页面结构。
  • 项目目录/pages/页面名/页面名.wxss: 页面样式文件。类似 CSS,作用于当前页面。优先级高于 app.wxss

特别说明:

  • WXML:微信自己的模板语言,结合基础组件、事件系统,可以构建出页面的结构。
  • WXSS:微信自己的样式语言,基于 CSS,做了一些扩充和优化,例如:rpx(响应式像素)。
  • JS:页面逻辑文件,负责页面的数据管理、事件响应等。
  • JSON:配置文件,控制小程序和页面的表现。

第一阶段:项目初始化与基本结构

步骤 1: 创建新项目

  1. 打开 微信开发者工具
  2. 点击左上角的 + 号,选择 新建项目
  3. 填写项目信息:
    • 项目名称Todo List
    • 项目目录:选择一个您想存放项目的文件夹。
    • AppID:填写您在微信公众平台获取的 AppID。
    • 后端服务:选择 不使用云服务 (本教程不涉及云开发)。
    • 语言JavaScript (默认)。
    • 模板小程序基础模板 (默认)。
  4. 点击 新建

现在,您应该能看到一个默认的项目结构,并在模拟器中显示一个简单的页面。

步骤 2: 理解初始文件结构

创建成功后,项目目录会包含以下主要文件:

1
2
3
4
5
6
7
8
9
10
11
├── project.config.json  // 项目配置文件
├── app.js // 小程序入口逻辑文件
├── app.json // 小程序全局配置
├── app.wxss // 小程序全局样式
├── sitemap.json // 站点地图
└── pages/ // 存放所有页面的目录
└── index/ // 首页目录
├── index.js // 首页逻辑
├── index.json // 首页配置
├── index.wxml // 首页结构
└── index.wxss // 首页样式

步骤 3: 配置 app.json (全局配置)

修改 app.json 文件,配置小程序的窗口表现。

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"pages": [
"pages/index/index"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#007bff",
"navigationBarTitleText": "我的待办事项",
"navigationBarTextStyle": "white"
},
"style": "v2",
"sitemapLocation": "sitemap.json"
}

保存后,您会看到模拟器的导航栏颜色和标题发生了变化。

步骤 4: 清理默认 index 页面内容

为了从零开始,我们先清空 pages/index/ 下的 wxmlwxss 文件内容。

  • pages/index/index.wxml:清空所有内容。
  • pages/index/index.wxss:清空所有内容。
  • pages/index/index.js:保留 Page({}) 结构,清空 datamethods,只留下基本骨架。
1
2
3
4
5
6
7
8
9
10
11
12
// pages/index/index.js
Page({
data: {
// 页面数据
},

onLoad() {
// 页面加载时触发
},

// 其他事件处理函数
})

第二阶段:构建 UI 界面 (WXML & WXSS)

现在我们开始构建 Todo List 的界面。

步骤 1: 设计 pages/index/index.wxml (页面结构)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!-- pages/index/index.wxml -->
<view class="container">
<!-- 1. 添加新待办事项区域 -->
<view class="input-area">
<input
class="todo-input"
placeholder="请输入待办事项"
bindinput="handleInputChange"
value="{{newTodo}}"
confirm-type="done"
bindconfirm="addTodo"
/>
<button class="add-button" bindtap="addTodo">添加</button>
</view>

<!-- 2. 待办事项列表 -->
<view class="todo-list">
<!-- 使用 wx:for 遍历 todos 数组 -->
<view
wx:for="{{todos}}"
wx:key="id"
class="todo-item {{item.completed ? 'completed' : ''}}"
data-id="{{item.id}}"
bindtap="toggleTodoStatus"
>
<text class="todo-text">{{item.text}}</text>
<text class="delete-button" data-id="{{item.id}}" catchtap="deleteTodo">×</text>
</view>

<!-- 列表为空时的提示 -->
<view wx:if="{{todos.length === 0}}" class="empty-tip">
暂无待办事项,快来添加吧!
</view>
</view>
</view>

代码解释:

  • <view>:小程序的容器组件,类似 div
  • <input>:输入框组件。
    • placeholder:提示文本。
    • bindinput:当输入框内容改变时触发的事件,用于更新 newTodo 数据。
    • value="{{newTodo}}":数据绑定,将输入框的值绑定到 newTodo 变量。
    • confirm-type="done":键盘右下角按钮显示“完成”。
    • bindconfirm="addTodo":当用户点击键盘上的“完成”按钮时触发,用于添加待办。
  • <button>:按钮组件。
    • bindtap="addTodo":当按钮被点击时触发 addTodo 方法。
  • wx:for="{{todos}}":列表渲染,遍历 todos 数组。
    • wx:key="id":指定列表中项目的唯一标识符,提高渲染效率,避免不必要的组件重新渲染。
    • class="todo-item {{item.completed ? 'completed' : ''}}":动态类名,根据 item.completed 状态添加 completed 类。
    • data-id="{{item.id}}":自定义属性,用于在事件处理函数中获取当前事项的 id
    • bindtap="toggleTodoStatus":点击整个事项区域时,切换其完成状态。
  • <text>:文本组件。
    • catchtap="deleteTodo":阻止事件冒泡 (避免点击删除按钮时同时触发 toggleTodoStatus),用于删除事项。
  • wx:if="{{todos.length === 0}}":条件渲染,当 todos 数组为空时显示提示信息。

步骤 2: 设计 pages/index/index.wxss (页面样式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/* pages/index/index.wxss */
.container {
padding: 20rpx;
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
height: 100vh; /* 让容器撑满整个视口高度 */
box-sizing: border-box;
}

/* 输入区域样式 */
.input-area {
display: flex;
margin-bottom: 30rpx;
align-items: center;
}

.todo-input {
flex: 1; /* 占据剩余空间 */
height: 80rpx;
border: 2rpx solid #eee;
padding: 0 20rpx;
border-radius: 10rpx;
font-size: 32rpx;
margin-right: 20rpx;
box-sizing: border-box; /* 确保内边距不会增加宽度 */
}

.add-button {
width: 160rpx;
height: 80rpx;
line-height: 80rpx;
font-size: 32rpx;
background-color: #007bff;
color: white;
border-radius: 10rpx;
padding: 0; /* 移除默认内边距 */
margin: 0; /* 移除默认外边距 */
}

/* 待办事项列表样式 */
.todo-list {
flex: 1; /* 列表占据剩余空间 */
overflow-y: auto; /* 允许列表内容滚动 */
}

.todo-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 25rpx 0;
border-bottom: 1rpx solid #f0f0f0;
font-size: 32rpx;
color: #333;
}

.todo-item:last-child {
border-bottom: none; /* 最后一个item没有下边框 */
}

.todo-text {
flex: 1;
margin-right: 20rpx;
word-break: break-word; /* 文本过长时自动换行 */
}

/* 已完成事项的样式 */
.todo-item.completed .todo-text {
text-decoration: line-through; /* 删除线 */
color: #999; /* 颜色变灰 */
}

/* 删除按钮样式 */
.delete-button {
color: #ff4d4f;
font-size: 40rpx;
font-weight: bold;
padding: 0 10rpx;
cursor: pointer;
}

/* 列表为空时的提示 */
.empty-tip {
text-align: center;
color: #999;
padding: 50rpx 0;
font-size: 30rpx;
}

代码解释:

  • rpx:微信小程序特有的尺寸单位,可以根据屏幕宽度进行自适应。例如,在 iPhone6 上,1rpx = 0.5px。
  • display: flex;flex-directionalign-itemsjustify-content:使用 Flexbox 布局实现元素的排列和对齐。
  • .todo-item.completed:当 todo-item 同时拥有 completed 类时生效。

保存这两个文件后,模拟器中会显示出 Todo List 的基本布局,但还不能进行交互。


第三阶段:实现核心逻辑 (JS)

现在我们为 Todo List 添加交互逻辑和数据管理。

步骤 1: 修改 pages/index/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// pages/index/index.js
Page({
data: {
newTodo: '', // 存储输入框的值
todos: [] // 存储待办事项列表,每个事项包含 id, text, completed
},

// 页面加载时触发:从本地存储加载数据
onLoad() {
this.loadTodos();
},

// 页面隐藏或退出时触发:保存数据到本地存储
onHide() {
this.saveTodos();
},

// 监听输入框内容变化
handleInputChange(e) {
this.setData({
newTodo: e.detail.value // 更新 newTodo 数据
});
},

// 添加待办事项
addTodo() {
const newTodoText = this.data.newTodo.trim(); // 获取输入框内容并去除首尾空格

if (newTodoText) { // 如果输入内容不为空
const newTodoItem = {
id: Date.now(), // 使用时间戳作为唯一ID
text: newTodoText,
completed: false
};

this.setData({
todos: [...this.data.todos, newTodoItem], // 将新事项添加到 todos 数组
newTodo: '' // 清空输入框
}, () => {
this.saveTodos(); // 数据更新后保存
});
}
},

// 切换待办事项的完成状态
toggleTodoStatus(e) {
const id = e.currentTarget.dataset.id; // 获取通过 data-id 传递过来的事项ID
const todos = this.data.todos.map(item => {
if (item.id === id) {
return { ...item, completed: !item.completed }; // 切换完成状态
}
return item;
});

this.setData({ todos }, () => {
this.saveTodos(); // 数据更新后保存
});
},

// 删除待办事项
deleteTodo(e) {
// 阻止事件冒泡,避免同时触发 toggleTodoStatus
// e.stopPropagation();
const id = e.currentTarget.dataset.id; // 获取事项ID
const todos = this.data.todos.filter(item => item.id !== id); // 过滤掉要删除的事项

this.setData({ todos }, () => {
this.saveTodos(); // 数据更新后保存
});
},

// 保存待办事项到本地存储
saveTodos() {
wx.setStorageSync('todos', this.data.todos); // 将 todos 数组存储到本地
console.log('Todos saved:', this.data.todos);
},

// 从本地存储加载待办事项
loadTodos() {
const todos = wx.getStorageSync('todos'); // 从本地获取 todos 数组
if (todos) { // 如果存在数据
this.setData({ todos }); // 更新页面数据
console.log('Todos loaded:', todos);
}
}
})

在微信开发者工具的右上角,点击 “详情” 按钮(图标通常是一个 i 或者类似列表的图标)。
在弹出的面板中,点击 “本地设置” 选项卡。
勾选 “开启条件编译” (Enable Enhanced Compilation)。
注意:如果已经勾选,尝试先取消勾选,编译一次,然后再重新勾选上。
同时确保 “ES6 转 ES5” 也是勾选状态。
点击工具栏上的 “编译” 按钮,查看报错是否消失。

代码解释:

  • data 对象
    • newTodo:用于存储用户在输入框中实时输入的内容。
    • todos:一个数组,存储所有待办事项。每个事项是一个对象 { id: number, text: string, completed: boolean }
  • onLoad() 生命周期:页面加载时执行,我们在此调用 loadTodos() 从本地存储加载数据。
  • onHide() 生命周期:当页面被隐藏(如用户切换到其他页面、退出小程序)时执行。我们在此调用 saveTodos() 将当前数据保存到本地存储,实现数据持久化。
  • handleInputChange(e)
    • e 是事件对象,e.detail.value 获取输入框的当前值。
    • this.setData({ key: value }):这是小程序更新页面数据的唯一方法。它会将数据从逻辑层发送到视图层,同时改变对应的 this.data 值。
  • addTodo()
    • trim() 方法去除输入字符串两端的空白字符。
    • Date.now():生成一个唯一的 ID (毫秒时间戳)。
    • [...this.data.todos, newTodoItem]:使用 ES6 的展开运算符,创建一个包含所有旧事项和新事项的新数组,然后通过 setData 更新。
  • toggleTodoStatus(e)
    • e.currentTarget.dataset.id:通过 data-id 属性获取当前点击元素的自定义数据。
    • map() 方法遍历 todos 数组,找到匹配 ID 的事项并切换其 completed 状态。{ ...item, completed: !item.completed } 也是 ES6 语法,用于创建一个新对象并覆盖 completed 属性。
  • deleteTodo(e)
    • e.stopPropagation():非常重要!防止点击删除按钮时,事件冒泡到父级 todo-item 元素,从而触发 toggleTodoStatus
    • filter() 方法遍历 todos 数组,过滤掉 ID 匹配的事项,从而实现删除。
  • saveTodos()loadTodos()
    • wx.setStorageSync(key, data):将数据同步写入本地缓存。
    • wx.getStorageSync(key):从本地缓存中同步获取指定 key 的内容。
    • 这些是微信小程序提供的本地存储API,类似于浏览器的 localStorage

保存所有文件后,现在您的Todo List小程序应该可以正常工作了!您可以尝试添加、标记完成、删除事项,并关闭小程序再打开,看看数据是否被保存。


第四阶段:调试与预览

  1. 在开发者工具中调试

    • 在开发者工具中,您可以直接看到模拟器的运行效果。
    • 点击工具栏上的 调试器 按钮,可以打开调试面板,类似于 Chrome 开发者工具。
      • Console:查看 console.log 输出,排查 JS 错误。
      • Elements:查看 WXML 结构和 WXSS 样式,动态修改样式。
      • Sources:调试 JS 代码,设置断点。
      • Storage:查看本地缓存数据 (wx.setStorageSync 存储的数据)。
      • Network:查看网络请求。
  2. 真机预览

    • 点击开发者工具右上角的 预览 按钮。
    • 微信会生成一个二维码,用您的微信扫描该二维码,即可在真机上预览小程序。这有助于检查不同设备上的兼容性和实际体验。

第五阶段:发布与上线 (简述)

当您完成开发并测试无误后,就可以考虑发布小程序了:

  1. 上传代码:在开发者工具右上角点击 上传 按钮,填写版本号和项目备注。代码将上传到微信公众平台。
  2. 提交审核:登录微信公众平台后台,进入 “开发管理” -> “版本管理”,您会看到刚才上传的版本。点击 提交审核。根据微信的审核规范,填写相关信息并等待审核。
  3. 发布上线:审核通过后,您可以选择 发布,小程序就会正式上线,用户可以在微信中搜索到并使用。

总结与下一步

恭喜您!您已经成功从零开发了一个具备基本功能的 Todo List 微信小程序,并了解了小程序的开发流程、核心概念和常用API。

您可以继续探索和优化:

  • 编辑功能:点击事项文本后,允许用户编辑内容。
  • 事项分类/筛选:添加分类功能,或按完成状态筛选显示。
  • 排序功能:例如按创建时间、重要程度排序。
  • 界面美化:使用更丰富的 WXSS 样式和动画效果。
  • 组件化:将待办事项列表项封装成自定义组件,提高代码复用性。
  • 用户登录/云开发:如果需要用户特定数据,可以结合微信登录和云开发(或自有后端服务)实现更复杂的功能。
  • API 调用:学习如何使用 wx.request 进行网络请求,与后端交互。

重要资源: