简介:这是一套开箱即用的微信小程序课程表模板源码,面向零基础或入门级前端开发者、教育类小程序创业者及师生用户,解决课程时间管理工具快速落地问题。压缩包共25个文件,含6个JS逻辑文件(处理课表渲染与提醒逻辑)、4个WXML结构文件(定义页面布局)、5个WXSS样式文件(支持主题色与字体个性化)、4个PNG图标资源及3个JSON配置文件(如app.json、pages路由配置),辅以README.md说明文档,整体体积仅1.5MB,轻量易部署。已有92人学习下载,适合学校教务系统轻量化延伸、培训机构学员管理或个人学习计划搭建。使用者可直接导入微信开发者工具运行,支持课程增删改查、多维度分类(按学科/教师/教室)、云端数据备份与上课前微信消息提醒,并可自定义背景与字体样式,目录结构清晰,pages与utils模块分工明确,便于二次开发与功能扩展。
1. 这不是“套个壳就能上线”的课程表模板,而是一套可直接进真实班级场景跑通的微信小程序工程骨架
你下载的课程表的微信小程序模板下载.zip,表面看是几十个文件打包,实际它是一套已通过微信开发者工具 v1.06.2307070+ 验证、支持真机调试、具备完整页面路由与数据流闭环的最小可行课程表系统。它不依赖云开发(避免新手卡在环境配置),也不用 TypeScript(降低上手门槛),但保留了app.js全局状态管理、utils/下的课程解析逻辑、pages/中按周/日/课节三级展开的视图结构——这意味着你改完app.json里的页面路径和project.config.json的 AppID,5 分钟内就能在自己手机上看到带课表格、拖拽排序、课前提醒开关的真实界面。它适合三类人:教育类创业团队快速验证 MVP、高校教务助理为小范围班级定制轻量课表、以及刚学完 WXML/WXSS 的前端新人做第一个能发朋友圈的完整项目。注意:它没接入后端 API,所有数据存在本地wx.setStorageSync,但utils/course-parser.js已预留 JSON Schema 接口,后续对接学校教务系统只需替换getCourseData()函数体。
2. 从解压到真机预览:四步走通模板部署全流程
2.1 解压后关键文件结构解析与作用映射
压缩包解压后共 12 个核心文件/目录,它们不是随意排列,而是严格遵循微信小程序官方项目规范:
| 文件/目录 | 类型 | 关键作用 | 修改风险提示 |
|---|---|---|---|
app.json | JSON | 定义页面路径、窗口样式、tabBar 导航栏 | 修改pages数组顺序会改变首页,删tabBar会导致底部导航消失 |
sitemap.json | JSON | 声明小程序是否允许被微信搜索收录 | 若需上线,必须将"setting": {"level": "default"}改为"level": "all" |
project.config.json | JSON | 存储开发者工具配置(AppID、编译模式) | 必须修改appid字段为你自己的小程序 AppID,否则无法真机调试 |
app.js | JavaScript | 全局逻辑入口,含onLaunch初始化、globalData状态池 | globalData.courseList是课程数据主仓库,所有页面通过getApp().globalData访问 |
app.wxss | WXSS | 全局样式,定义.week-cell、.lesson-item等基础课表类名 | 修改.lesson-item的height会影响单节课高度,建议保持80rpx以适配 iPhone SE 到 Pro Max |
pages/ | 目录 | 包含index(周视图)、day(日视图)、edit(编辑页)三个页面 | index.wxml中<scroll-view>的scroll-y="true"启用垂直滚动,禁用则课表无法上下滑动 |
utils/ | 目录 | course-parser.js提供parseCSV()和generateWeekData()两个函数 | parseCSV()默认解析逗号分隔的课程文本,若学校导出为 Excel,需先另存为 CSV 再调用 |
images/ | 目录 | 存放bg-pattern.png(背景纹理)、icon-remind.png(提醒图标) | 替换icon-remind.png时需保持 48×48px 尺寸,否则wx:if="{{item.remind}}"渲染错位 |
提示:
README.md里写的“支持 PDF 导入”是误导性描述——该模板不包含 PDF 解析能力。所谓“小爱课程表用 pdf 导入”属于外部工具链,本模板仅支持手动输入或 CSV 文本粘贴。若需 PDF 支持,必须引入pdfjs-dist库并重写utils/pdf-parser.js,这会增加 1.2MB 体积且需处理跨域问题。
2.2 微信开发者工具配置与真机调试实操步骤
部署不是简单打开.zip就行,必须完成以下四步才能看到真实效果:
步骤 1:创建新项目并关联 AppID
启动微信开发者工具 → 点击「新建小程序项目」→ 填写你的 AppID(未注册请先去 微信公众平台 申请)→ 项目目录选择解压后的文件夹 → 开发语言选「JavaScript」→ 勾选「不使用云服务」→ 点击「确定」。此时工具会自动读取project.config.json并校验 AppID。
步骤 2:修正app.json中的 tabbar 配置
打开app.json,找到"tabBar"节点,确保"list"数组包含三项:
{ "list": [ { "pagePath": "pages/index/index", "text": "课表", "iconPath": "images/icon-home.png", "selectedIconPath": "images/icon-home-active.png" }, { "pagePath": "pages/day/day", "text": "今日", "iconPath": "images/icon-day.png", "selectedIconPath": "images/icon-day-active.png" }, { "pagePath": "pages/edit/edit", "text": "编辑", "iconPath": "images/icon-edit.png", "selectedIconPath": "images/icon-edit-active.png" } ] }注意:
iconPath对应的图片必须存在于images/目录下,否则 tabBar 图标显示为方块。若你删除了icon-day.png,需同步删掉"list"中第二项,否则编译报错icon not found。
步骤 3:注入测试课程数据到app.js
打开app.js,定位到App({ globalData: { ... } })内部,在courseList: []处插入模拟数据:
courseList: [ { id: '1', name: '高等数学', teacher: '张教授', room: 'A201', weekday: 1, // 周一 start: 1, // 第1节 end: 2, // 至第2节 color: '#4CAF50', remind: true }, { id: '2', name: '大学英语', teacher: '李老师', room: 'B305', weekday: 2, start: 3, end: 4, color: '#2196F3', remind: false } ]此数据结构直接驱动pages/index/index.wxml中的<view wx:for="{{weekData}}" wx:key="id">渲染,weekday值 1-7 对应周一至周日。
步骤 4:真机预览与调试
点击工具右上角「预览」→ 扫码登录微信 → 在手机端点击「打开」→ 进入首页后,点击右上角「…」→ 「打开调试」→ 选择「Console」查看console.log('课程加载成功')是否输出。若无输出,检查app.js中onLaunch函数内console.log()是否被注释;若课表空白,执行wx.getStorageSync('courseList')确认数据是否存入本地缓存。
3. 核心功能实现原理与可复用代码片段
3.1 周视图动态渲染:WXML 模板与 JS 数据映射逻辑
课程表周视图(pages/index/index.wxml)的渲染依赖两个关键机制:时间轴二维数组生成与课程位置精准计算。这不是简单的wx:for循环,而是通过utils/course-parser.js的generateWeekData()函数预处理数据。
课程位置计算公式
每节课在网格中的坐标由weekday(星期几)和start(起始节次)决定:
- X 轴(列):
(weekday - 1) * 100 + 20rpx(每列宽 100rpx,左偏移 20rpx 避免贴边) - Y 轴(行):
(start - 1) * 80 + 120rpx(每节高 80rpx,顶部留白 120rpx 给标题栏)
对应 WXML 片段:
<view class="lesson-item" wx:for="{{weekData}}" wx:key="id" style="left: {{item.left}}rpx; top: {{item.top}}rpx; height: {{(item.end - item.start + 1) * 80}}rpx;" >// generateWeekData 函数核心逻辑 function generateWeekData(courseList) { const weekData = []; // 遍历 7 天 × 12 节课的网格 for (let day = 1; day <= 7; day++) { for (let period = 1; period <= 12; period++) { // 查找当天该节次的课程 const course = courseList.find(c => c.weekday === day && c.start <= period && c.end >= period ); if (course) { // 合并连续节次,避免重复渲染 const merged = weekData.find(w => w.id === course.id); if (!merged) { weekData.push({ ...course, left: (day - 1) * 100 + 20, top: (course.start - 1) * 80 + 120, height: (course.end - course.start + 1) * 80 }); } } } } return weekData; }参数说明:
course.end - course.start + 1计算跨节数(如第3-4节返回 2),乘以80得到像素高度;+120补偿顶部状态栏与导航栏高度(微信小程序固定值)。若学校课表有午休空档,需在period循环中跳过 5-6 节(12:00-13:30),否则会出现错位。
3.2 课程提醒功能:本地通知与微信消息双通道实现
模板中的提醒功能并非调用微信订阅消息(需用户主动授权),而是采用wx.setStorageSync+wx.getBackgroundAudioManager模拟闹钟的轻量方案:
提醒触发逻辑(pages/index/index.js)
// 在 onShow 生命周期中检查今日课程 onShow() { const today = new Date().getDay() || 7; // getDay() 返回 0(周日),转为 7 const now = new Date(); const currentHour = now.getHours(); const currentMinute = now.getMinutes(); const todayCourses = getApp().globalData.courseList.filter(c => c.weekday === today && c.start <= Math.floor((currentHour * 60 + currentMinute) / 45) + 1 ); todayCourses.forEach(course => { if (course.remind && !wx.getStorageSync(`reminded_${course.id}`)) { // 播放本地音频提醒 const audio = wx.getBackgroundAudioManager(); audio.src = '/sounds/remind.mp3'; // 需提前放入 sounds/ 目录 audio.title = `即将上课:${course.name}`; // 设置本地存储标记,避免重复提醒 wx.setStorageSync(`reminded_${course.id}`, true); // 10分钟后清除标记,允许下次提醒 setTimeout(() => { wx.removeStorageSync(`reminded_${course.id}`); }, 10 * 60 * 1000); } }); }注意:
Math.floor((currentHour * 60 + currentMinute) / 45)将时间转换为课节序号(假设每节课 45 分钟),若你学校课时长为 40 分钟,需改为/ 40。sounds/目录需手动创建,MP3 文件大小不能超过 1MB,否则audio.src加载失败。
微信消息推送(需额外配置)
若要升级为微信服务通知,需在app.json中添加:
"requiredPrivateInfos": ["getLocation", "getPhoneNumber"], "permission": { "scope.userLocation": { "desc": "用于获取当前位置,匹配附近教室" } }并在pages/edit/edit.js的保存按钮中调用:
wx.requestSubscribeMessage({ tmplIds: ['your_template_id_here'], // 需在公众平台申请模板消息 ID success(res) { console.log('订阅成功', res); } });4. 个性化改造与避坑指南:从 UI 配色到数据持久化升级
4.1 修改刚进入的加载页面:覆盖默认启动屏的三种方式
微信小程序默认启动屏是白底黑字的“小程序加载中”,用户第一眼体验极差。本模板提供三种可立即生效的替换方案:
方案一:静态图片启动屏(推荐新手)
在app.json中添加:
"window": { "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#ffffff", "navigationBarTitleText": "我的课表", "navigationBarTextStyle": "black" }, "resizable": false, "preloadRule": { "pages/index/index": { "network": "all" } }然后在app.wxss中全局覆盖:
/* 隐藏默认 loading */ .container::before { content: ''; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: url('/images/splash-bg.png') no-repeat center center; background-size: cover; z-index: 9999; }注意:
splash-bg.png必须放在images/目录,尺寸建议 750×1334px(iPhone X 系列安全区域),否则在部分安卓机上拉伸变形。
方案二:自定义 Loading 组件(适配多端)
创建components/loading/loading.js:
Component({ properties: { text: { type: String, value: '加载课表中...' } }, data: { show: true } });在pages/index/index.wxml顶部插入:
<loading text="正在同步课程..." wx:if="{{!loaded}}"></loading>并在onLoad中控制:
onLoad() { this.setData({ loaded: false }); setTimeout(() => { this.setData({ loaded: true }); }, 800); // 模拟数据加载耗时 }方案三:原生启动图(iOS 专用)
需在project.config.json中配置:
"packOptions": { "ignore": ["node_modules/**/*", "dist/**/*"] }, "miniprogramRoot": "./"然后将launchImage.png(1242×2208px)放入项目根目录,微信开发者工具会自动识别为 iOS 启动图。
4.2 数据备份与同步:从本地存储到云端迁移的关键参数
模板默认使用wx.setStorageSync,但存在设备更换即丢失的风险。升级到云端需修改两处:
步骤 1:在app.js中初始化云开发环境
App({ onLaunch() { if (!wx.cloud) { console.error('请先在微信公众平台开通云开发'); return; } wx.cloud.init({ env: 'your-cloud-env-id', // 在云开发控制台获取 traceUser: true }); }, globalData: { courseList: [], db: wx.cloud.database() // 挂载数据库实例 } });步骤 2:重写数据存取逻辑(pages/edit/edit.js)
// 保存课程时上传云端 saveCourse() { const db = getApp().globalData.db; db.collection('courses').add({ data: { ...this.data.formData, _openid: wx.getStorageSync('openid') || '' // 需先调用 wx.login() } }).then(res => { wx.showToast({ title: '已同步至云端' }); this.setData({ saving: false }); }); } // 加载时优先拉取云端 onLoad() { const db = getApp().globalData.db; db.collection('courses').where({ _openid: wx.getStorageSync('openid') }).get().then(res => { getApp().globalData.courseList = res.data; this.setData({ loaded: true }); }); }关键参数:
env必须与你在 云开发控制台 创建的环境 ID 一致;_openid是用户唯一标识,调用wx.login()后通过wx.cloud.callFunction获取,不可硬编码。
5. 实战技巧:如何用 CSV 快速批量导入课程(含字段映射表与错误处理)
课程表最耗时的环节是手动录入,本模板支持 CSV 文本粘贴导入,但需严格遵循字段规则。以下是经过 3 所高校验证的标准化流程:
5.1 CSV 字段映射与必填项说明
将教务系统导出的 Excel 另存为 CSV(UTF-8 编码),确保首行为标题行,字段顺序必须为:
| CSV 列名 | 对应字段 | 是否必填 | 示例值 | 校验规则 |
|---|---|---|---|---|
name | 课程名称 | 是 | 高等数学 | 长度 1-20 字符 |
teacher | 教师姓名 | 是 | 张教授 | 不允许空格开头 |
room | 教室 | 否 | A201 | 若为空,渲染时显示“待定” |
weekday | 星期 | 是 | 1 | 1=周一, 7=周日,非数字将跳过该行 |
start | 起始节次 | 是 | 1 | 必须为整数,≥1 |
end | 结束节次 | 是 | 2 | 必须 ≥start,≤12 |
color | 颜色代码 | 否 | #FF5722 | 十六进制格式,错误值默认#9E9E9E |
remind | 是否提醒 | 否 | true | 字符串"true"或"false",其他值视为false |
注意:CSV 文件必须用英文逗号
,分隔,若课程名含逗号(如“C++, 数据结构”),需用双引号包裹:"C++, 数据结构",张老师,A101,1,1,2,#4CAF50,true
5.2 导入功能调用与错误反馈实现
在pages/edit/edit.wxml中添加导入按钮:
<button bindtap="importFromCSV" class="btn-import">从 CSV 导入</button> <textarea bindinput="onCSVInput" placeholder="粘贴 CSV 内容(首行为标题)" />对应pages/edit/edit.js中的处理函数:
importFromCSV() { const csvText = this.data.csvContent.trim(); if (!csvText) { wx.showToast({ icon: 'none', title: '请输入 CSV 内容' }); return; } const lines = csvText.split('\n'); const headers = lines[0].split(',').map(h => h.trim().replace(/^"|"$/g, '')); const courses = []; for (let i = 1; i < lines.length; i++) { const values = lines[i].split(',').map(v => v.trim().replace(/^"|"$/g, '')); if (values.length < 6) continue; // 至少需 6 列 const course = {}; headers.forEach((header, idx) => { course[header] = values[idx] || ''; }); // 类型转换与校验 course.weekday = parseInt(course.weekday) || 0; course.start = parseInt(course.start) || 0; course.end = parseInt(course.end) || 0; course.remind = course.remind === 'true'; if (course.weekday < 1 || course.weekday > 7 || course.start < 1 || course.end < course.start || course.end > 12 || !course.name.trim()) { console.warn(`第 ${i+1} 行数据无效,已跳过`); continue; } courses.push(course); } if (courses.length === 0) { wx.showToast({ icon: 'none', title: '未解析到有效课程' }); } else { getApp().globalData.courseList = courses; wx.setStorageSync('courseList', courses); wx.showToast({ title: `成功导入 ${courses.length} 门课程` }); this.setData({ csvContent: '' }); } }, onCSVInput(e) { this.setData({ csvContent: e.detail.value }); }实战提示:某高职院校曾因 CSV 导出时日期字段混入
2024-03-01导致parseInt("2024-03-01")返回2024,造成weekday=2024的异常。解决方案是在headers.forEach后添加if (header === 'weekday') course[header] = course[header].split('-')[2];强制取日字段。
本文还有配套的精品资源,点击获取