目录
一、开发环境
Node.JS v20.19.1
MySQL数据库 5.5.40
微信开发者助手 1.06.2503310
二、演示视频
基于微信小程序开发的背单词App
三、设计详情(部分)
登录页
<view class="userinfo" wx:if="{{showLogin}}">
<block wx:if="{{canIUseNicknameComp}}">
<button class="avatar-wrapper" open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">
<image class="avatar" src="{{userInfo.avatarUrl}}"></image>
</button>
<view class="nickname-wrapper">
<text class="nickname-label">昵称</text>
<input class="nickname-input" type="nickname" placeholder="请输入昵称" bind:change="onInputChange" value="{{userInfo.user_name}}" />
</view>
<view class="phone-wrapper">
<text class="phone-label">手机号</text>
<input class="phone-input" type="number" placeholder="请输入手机号" bind:change="onPhoneChange" value="{{userInfo.user_phone}}" />
</view>
<view class="password-wrapper">
<text class="password-label">密码</text>
<input class="password-input" password="true" placeholder="请输入密码" bind:change="onPasswordChange" value="{{userInfo.user_password}}" />
</view>
<button class="login-btn" bindtap="handleLogin">登录</button>
</block>
</view>
实现了微信小程序的用户注册功能,整合了微信登录、表单校验、头像上传、后端交互等模块,流程清晰且具备容错机制。
通过本地存储管理登录状态,确保用户体验连贯性。
1. 初始化与登录检查
- 页面加载时首先检查用户是否已登录(通过本地存储的openid判断),已登录则跳转首页,未登录则获取微信openid并查询是否已注册。未注册用户显示登录/注册界面。
2. 用户信息处理
- 提供表单输入处理函数,包括用户名、手机号、密码的输入校验(去空格、格式检查)。
- 支持头像上传功能,未上传时使用默认头像,并标记上传状态。
3. 注册逻辑
- 提交前验证表单完整性(头像、用户名、手机号、密码),对手机号格式(11位数字)和密码长度(≥6位)进行校验。
- 调用微信登录接口获取openid,通过后端接口注册用户,成功后将openid和头像存入本地存储,跳转首页。
4. 异常处理
- 对网络请求、手机号冲突等错误进行捕获,通过Toast提示用户具体错误(如“手机号已存在”)。
- 使用加载遮罩层防止用户误操作,流程结束统一隐藏加载状态。
首页
<view class="container">
<!-- 打卡天数 -->
<view class="checkin-section">
<view class="checkin-content">
<text class="checkin-title">已连续打卡</text>
<text class="checkin-days">{{checkinDays}} 天</text>
<text class="checkin-subtitle">每日坚持学习效果更好</text>
</view>
<view class="checkin-calendar">
<!-- 这里可以放置日历图标或其他装饰元素 -->
<image src="/images/calendar.png" mode="aspectFit" class="calendar-icon"></image>
</view>
</view>
<!-- 学习进度 -->
<view class="progress-section">
<image src="/images/bg.png" mode="aspectFill" class="bg-image"></image>
<text class="section-title">{{vocabularyPack}}</text>
<view class="progress-content">
<view class="show-progress-text">
<text>已完成{{completionRate}}%</text>
<text>{{learnedCount}}/{{totalCount}}词</text>
</view>
<progress percent="{{completionRate}}" stroke-width="6" activeColor="#00b1e7" backgroundColor="#e5e5e5" />
</view>
</view>
<!-- 今日任务 -->
<view class="task-section">
<text class="task-title">-今日任务-</text>
<view class="task-stats">
<view class="stat-item">
<text class="stat-number">{{dailyGoal}}</text>
<text class="stat-label">新词数</text>
</view>
<view class="stat-item">
<text class="stat-number">{{reviewWordsCount}}</text>
<text class="stat-label">复习单词</text>
</view>
<view class="stat-item">
<text class="stat-number">{{unreviewedWordsCount}}</text>
<text class="stat-label">未复习单词</text>
</view>
</view>
</view>
<!-- 开始学习按钮 -->
<view class="button-container">
<button class="start-button" bindtap="startLearning">开始学习</button>
</view>
</view>
该页面是单词学习的主控页,整合了用户进度管理、学习任务调度、数据同步等功能。
通过本地缓存优化性能,结合后端接口确保数据一致性,逻辑分层清晰(初始化 → 加载数据 → 交互响应)。
支持动态切换考试类型(四级/六级),并实时更新学习进度和复习任务提醒。
1. 时间处理与初始化
- 使用 `getBeijingTime()` 获取当前北京时间(格式:`yyyy/MM/dd`),用于打卡和学习记录的日期判断。
- 页面初始化时设置默认数据(如词汇包类型、学习进度等),并调用 `loadUserData()` 加载用户学习数据。
2. 用户数据加载与检查
- 通过本地存储获取用户 `openid`,未登录则跳转至登录页。
- 调用 `checkUserProgress()` 从后端获取用户学习进度(如连续打卡天数、每日目标、已学单词数),若用户无记录则调用 `createDefaultProgress()` 初始化默认数据。
- 动态计算学习完成率(`completionRate`),并拉取词汇包总单词数(`totalCount`)和复习相关数据(未复习单词数、需复习单词数)。
3. 学习逻辑控制
- 点击“开始学习”时,根据优先级跳转:
- 优先复习未完成的单词(`unreviewedWordsCount > 0` 时进入复习页)。
- 若今日任务已完成(通过本地存储的 `lastCompleteTime` 和 `wordsLearnedToday` 判断),提示用户无需重复学习。
- 正常情况进入学习页面,携带参数(如每日目标、考试类型)。
4. 数据同步与容错
- 所有后端请求(如获取复习单词数、词汇总数)均包含成功/失败回调,失败时显示 Toast 提示并记录错误日志。
- 本地缓存关键数据(如打卡日期、今日已学单词数),用于快速判断任务状态,避免频繁请求后端。
学习生词
// 页面加载时触发
onLoad(options) {
// 解析从上个页面传递过来的参数
this.parseOptions(options);
// 获取用户 OpenID 并设置到 data 中
const user_openid = wx.getStorageSync('user_openid');
this.setData({
user_openid
});
// 判断今天是否已打卡(通过比较日期)
const lastCheckInDate = wx.getStorageSync('lastCheckInDate');
this.setData({
hasCheckedInToday: lastCheckInDate === getBeijingTime()
});
// 加载今天已学习的单词数量
const wordsLearnedToday = wx.getStorageSync('wordsLearnedToday') || 0;
this.setData({
wordsLearnedToday
});
// 检查用户当前的学习进度
this.checkUserProgress();
// 创建音频上下文对象(用于播放发音)
this.setData({
audioContext: wx.createInnerAudioContext()
});
},
// 解析跳转页面传入的参数
parseOptions(options) {
if (!options) {
console.error("未接收到参数,请检查跳转逻辑");
return;
}
const dailyGoal = parseInt(options.dailyGoal) || 0;
const reviewWordsCount = parseInt(options.reviewWordsCount) || 0;
const word_type = parseInt(options.word_type) || 4;
this.setData({
dailyGoal,
reviewWordsCount,
word_type,
todayNewWords: dailyGoal,
todayReviewWords: reviewWordsCount
});
console.log("解析参数结果:", {
dailyGoal,
reviewWordsCount,
word_type
});
},
// 向服务器请求用户当前进度
checkUserProgress() {
wx.request({
url: api.mysql + '/getUserCurrentProgress',
method: 'GET',
data: {
user_openid: this.data.user_openid
},
success: (res) => {
if (res.data.message === '查询成功') {
const currentProgress = res.data.data.current_progress;
this.setData({
currentProgress
});
// 若今日任务已完成,则提示用户
if (this.data.wordsLearnedToday >= this.data.todayNewWords) {
wx.showToast({
title: '今日学习已完成!',
icon: 'success'
});
return;
}
// 获取下一个单词进行学习
this.getNextWord();
} else {
wx.showToast({
title: '获取进度失败',
icon: 'none'
});
}
},
fail: (err) => {
console.error('获取用户进度失败:', err);
wx.showToast({
title: '网络错误',
icon: 'none'
});
}
});
},
该页面是单词学习的核心交互页,整合了单词展示、发音播放、进度更新、复习管理等功能。
通过本地缓存优化性能,结合后端接口确保数据一致性,逻辑分层清晰(初始化 → 学习 → 进度同步 → 打卡)。
支持动态切换考试类型,实时反馈学习状态,并在页面卸载时释放资源(如音频上下文)。
1. 时间管理与初始化
- 使用 `getBeijingTime()` 获取北京时间(`yyyy/MM/dd`),用于打卡和学习记录的日期判断。
- 页面加载时解析参数(如每日目标、复习单词数),初始化音频上下文(用于单词发音),并检查用户今日打卡状态和已学单词数。
2. 学习流程控制
- 单词获取:根据考试类型(四级/六级)和当前进度,从后端获取下一个单词数据(单词、音标、例句)。
- 交互功能:支持播放单词发音、显示/隐藏例句,点击“我认识”后更新学习进度并触发复习列表添加。
- 任务完成判断:通过比较 `wordsLearnedToday` 和 `dailyGoal`,提示用户今日任务完成或继续学习。
3. 数据同步与状态管理
- 本地缓存:存储关键数据(如已学单词数、打卡日期),避免频繁请求后端。
- 进度更新:用户认识单词后,同步更新本地和数据库进度(区分四级/六级字段),并检查是否触发打卡逻辑。
- 复习列表:将已学单词添加到复习列表,避免重复添加。
4. 打卡与容错机制
- 自动打卡:完成当日任务且未打卡时,自动调用 `checkIn()` 更新连续打卡天数。
- 网络容错:所有请求均处理成功/失败状态,失败时显示 Toast 提示并记录日志(如获取单词失败、打卡失败)。
我的生词本
<view class="container">
<!-- 单词信息 -->
<view class="card word-card">
<view class="word-top">
<text class="word">{{ wordDetail.word }}</text>
<image src="/images/audio.png" class="audio-icon" data-word="{{ wordDetail.word }}" bindtap="playAudio" />
</view>xx
<text class="phonetic">{{ wordDetail.word_phonetic_symbol }}</text>
</view>
<!-- 中文释义 -->
<view class="card">
<view class="section-header">
<image src="/images/zh.png" class="section-icon" />
<text class="section-title">中文释义</text>
</view>
<view class="divider"></view>
<view class="section-content">{{ wordDetail.words_chinese }}</view>
</view>
<!-- 英文例句 -->
<view class="card">
<view class="section-header">
<image src="/images/en.png" class="section-icon" />
<text class="section-title">英文例句</text>
</view>
<view class="divider"></view>
<view class="section-content">{{ wordDetail.word_example_sentence }}</view>
<view class="example-translation">{{ wordDetail.word_example_translation }}</view>
</view>
<!-- 操作按钮 -->
<button class="save-btn" bindtap="addToUnknown">+ 加入生词本</button>
</view>
1. 核心功能
- 这是一个生词管理页面,主要实现生词展示、发音播放、删除生词等功能
- 使用有道词典API实现单词发音功能
- 支持循环浏览生词列表
2. 数据管理
- 从本地存储获取用户openid作为身份标识
- 通过接口`/getUnknownWords`获取用户的生词列表
- 使用`/deleteUnknownWord`接口删除指定生词
- 采用循环索引机制(currentIndex)实现生词轮播
3. 交互设计
- 进入页面自动加载生词并播放第一个单词发音
- 点击"下一个"按钮切换到下一个单词并自动播放
- 删除操作需要二次确认,避免误操作
- 所有网络请求都有成功/失败的状态反馈
4. 技术实现
- 使用`wx.createInnerAudioContext`创建音频播放器
- 设置`obeyMuteSwitch = false`确保静音模式下也能播放
- 采用回调函数确保数据更新后再执行相关操作
四、项目源码
👇👇👇👇👇快捷方式👇👇👇👇👇