今天手把手的带大家实现一款答题类的题库小程序,如果着急的话,可以直接去看文末源码.下载与项目部署。
考研题库小程序云开发实战,完整版提供给大家学习。题库小程序,基于云开发的微信答题小程序,软件架构是微信原生小程序+云开发。
一、项目预览
1、页面结构
首页
答题页
结果页
我的页
排行榜页
答题历史页
登录页
使用指引页
2、功能结构
实现页面间跳转功能
微信授权登录
获取微信头像和昵称等
按科目分类
题库随机抽题算法
支持单选、判断、多选
实现用云开发实现查询题库功能
实现动态题目数据绑定
答题交互逻辑
切换下一题
答题进度显示
提交答卷保存到云数据库集合
系统自动判分
答题结果页从云数据库查询答题成绩
实现转发分享答题成绩功能
查询历史成绩
取最佳成绩进行排名
推荐分享
在线客服
意见反馈
3、小程序端
效果预览:
小程序[考研刷题小博士]
小程序[考研刷题小博士]
1)首页
①使用了swiper组件实现轮播图效果,里面使用了image标签展示图片;
②按科目分类的题库;
2)排名页
①对应四个科目,按照得分由高到底进行排名;
②如果同一个人答题多次,取个人最佳成绩进行排名;
3)我的页
①展示个人信息,头像、昵称;
②功能按钮区域,考试记录、推荐给好友、联系客服、意见反馈、使用指引;
4)答题页
①展示当前答题者的信息,头像、昵称;
②答题总数,以及当前答题进度;
③题型、题目、选项、切换下一题按钮;
5)结果页
①展示考生信息,头像、昵称;
②科目、题目总数、得分、答对题数、答错题数、正确率;
③再打一次、返回首页、分享成绩给好友;
6)答题记录页
答题科目、答题时间;
7)登录页
可以进行微信授权登录获取头像、昵称,也可以自定义填写头像、昵称;
8)使用指引页
自定义使用指引或说明;
4、CMS后台
题库管理(新增、查看、搜索、编辑、删除、导入、导出)-管理员权限
1)题库列表
2)条件筛选搜索
3)关键词搜索
4)新增题目
5)编辑题目
5、数据库
云开发数据库,题目数据表、答题记录数据表、答题成绩数据表;
二、学习资料
1、搭建教程
详细讲解手把手搭建教程,我已在前段时间免费分享给大家,请大家移步我的主页翻翻,查阅历史文章吧;
2、配套源码
目前源码和配套资源文件暂时不免费,毕竟创作不易,如果有需要的同学可以私聊蒙哥,拿米来换;
3、问题解答(●’◡’●)
另外,蒙哥提供配套解答服务。当然了,知识付费时代蒙哥解答是要米的,毕竟食不饱力不足才美不外现。你在学习过程中有任何开发问题,或者工作中遇到任何前端问题,都可以来找蒙哥。
目前可以解答如下问题:
小程序方面的问题;
云开发方面的问题;
毕设方面的问题;
html+css+JavaScript方面的问题;
前端开发的问题;
面试找工作方面的问题等。
三、项目创建
1、环境准备
1.1、 注册小程序账号
到微信公众平台进行注册微信小程序账号。建议使用全新的邮箱,没有注册过其他小程序或者公众号的。
1.2 、获取APPID
由于后期调⽤微信⼩程序的接⼝等功能,需要索取开发者的⼩程序中的 APPID ,所以在注册成功后, 可登录,然后获取APPID。
点击开发管理,选择开发设置下面的appid:
1.3、 下载开发工具
选择开发工具进行下载,并安装:
2、初始化项目
2.1、 打开微信开发者⼯具
注意:第⼀次登录的时候,需要扫码登录。
2.2、 新建⼩程序项⽬
点击小程序选择添加
2.3、 填写项目信息
注意:后端服务选择“微信云开发”
四、项目结构以及详解
1、项目目录结构
下面让我们来看看新建小程序应用,初始化后的考研刷题小程序项目目录结构吧。
2、小程序配置文件
一个小程序应用程序会包括最基本的两种配置文件。一种是全局的 app.json ,另一种是页面的page.json。
2.1、全局配置app.json
小程序根目录下的app.json文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。
以考研刷题小程序为栗子看看,以下是一个包含了部分常用配置选项的app.json:
{"pages": ["pages/index/index","pages/home/home","pages/test/test","pages/result/result","pages/history/history","pages/rank/rank","pages/guide/guide","pages/my/my"],"window": {"backgroundTextStyle": "light","navigationBarBackgroundColor": "#fff","navigationBarTitleText": "考研刷题小博士","navigationBarTextStyle": "black"},"tabBar": {"color": "#aaa","selectedColor": "#ffa517","borderStyle": "black","backgroundColor": "#ffffff","list": [{"pagePath": "pages/home/home","iconPath": "/image/sy2.png","selectedIconPath": "/image/sy2-a.png","text": "题库"},{"pagePath": "pages/rank/rank","iconPath": "/image/zxly2.png","selectedIconPath": "/image/zxly2-a.png","text": "排名"},{"pagePath": "pages/my/my","iconPath": "/image/wd2.png","selectedIconPath": "/image/wd2-a.png","text": "我的"}]},"sitemapLocation": "sitemap.json"}
pages:页面路径列表;
window:用于设置小程序的状态栏、导航条、标题、窗口背景色;
tabBar:底部 tab 栏的表现;
sitemapLocation:指明 sitemap.json 的位置;
注意:这里只解读我这个考研刷题小程序项目里面使用到的配置项,更多配置项自行去技术官网查看。
2.1.1、pages
文件名不需要写文件后缀,框架会自动去寻找对应位置的 .json, .js, .wxml, .wxss 四个文件进行处理。未指定 entryPagePath 时,数组的第一项代表小程序的初始页面(首页)。
"pages": ["pages/index/index","pages/home/home","pages/test/test","pages/result/result","pages/history/history","pages/rank/rank","pages/guide/guide","pages/my/my"]
2.1.2、window
backgroundColor:窗口的背景色;
backgroundTextStyle: 下拉 loading 的样式,仅支持 dark / light;
navigationBarBackgroundColor:导航栏背景颜色;
navigationBarTitleText:导航栏标题文字内容;
navigationBarTextStyle:导航栏标题颜色,仅支持 black / white;
2.1.3、tabbar
如果小程序是一个多 tab 应用(客户端窗口的底部或顶部有 tab 栏可以切换页面),可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页面。
其中 list 接受一个数组,只能配置最少 2 个、最多 5 个 tab。tab 按数组的顺序排序,每个项都是一个对象。而在考研刷题小程序项目里面,我配置了三个,分别是题库、排名、我的。
"tabBar": {"color": "#aaa","selectedColor": "#ffa517","borderStyle": "black","backgroundColor": "#ffffff","list": [{"pagePath": "pages/home/home","iconPath": "/image/sy2.png","selectedIconPath": "/image/sy2-a.png","text": "题库"},{"pagePath": "pages/rank/rank","iconPath": "/image/zxly2.png","selectedIconPath": "/image/zxly2-a.png","text": "排名"},{"pagePath": "pages/my/my","iconPath": "/image/wd2.png","selectedIconPath": "/image/wd2-a.png","text": "我的"}]}
2.2、页面配置
每一个小程序页面也可以使用同名.json文件来对本页面的窗口表现进行配置,页面中配置项会覆盖app.json的window中相同的配置项。
注意:这里只解读我这个考研刷题小程序项目里面使用到的配置项,更多配置项自行去技术官网查看。
例如,首页的配置index.json:
{"navigationBarBackgroundColor": "#ffffff","navigationBarTextStyle": "black","navigationBarTitleText": "考研刷题小博士","backgroundColor": "#eeeeee","backgroundTextStyle": "light"}
backgroundColor:窗口的背景色;
backgroundTextStyle: 下拉 loading 的样式,仅支持 dark / light;
navigationBarBackgroundColor:导航栏背景颜色;
navigationBarTitleText:导航栏标题文字内容;
navigationBarTextStyle:导航栏标题颜色,仅支持 black / white;
五、所用技术栈及知识讲解
1、模板语法
1.1、view标签和text标签
我们现在做的是微信小程序,所以,要使用它的语法。WXML(WeiXin Markup Language)是微信小程序框架设计的一套标签语言。
注意!不要被官方的很官方的概念唬住了,其实就是简单的标签。不信,咱们举个栗子类比看看。相信大多数小伙伴,即使没有做过开发的都听过,html的div和span。
div => viewspan => text
view其实相当于div,都是块级元素,也就是会换行的;
text相当于span,都是行内元素,也就是不会换行的。
动手试试吧,在index.wxml直接使用这两个标签就明白了。
<view> 马原 </view><view> 毛中特 </view><view><text> 思修 </text><text> 近代史 </text></view>
什么?还有点迷糊?这样看呢!
保姆级演示,明白了“view是块级元素,会换行的;text是行内元素,不会换行的”这句话了没?
或许我以后不会这么讲了,因为实在是太太太基础了。简单的事情,只说一遍。
不明白不要紧,就像公式,你不用知道是怎么来的,你只要记住公式是怎么用的就行了。
毕竟咱们做的是应用层面的开发嘛,它提供什么API,知道怎么用的,然后直接去使用就行了。如果能举一反三,就更好了。
1.2、数据绑定
在js的data中定义变量:
data:{title:"考研题库小程序",num:50,isLogin:true,user:{nickName:"姑苏洛言",age:20},isChecked:true}
在 wxml中 直接使用:
<!-- 字符串类型 --><view>{{title}}</view><!-- 数字类型 --><view>{{num}}</view><!-- 布尔类型 --><view>{{isLogin?'你好,xx会员':'请授权登录'}}</view><viewwx:if="{{isLogin}}">{{user.nickName}}</view><viewwx:else="{{isLogin}}"> 请先登录 </view><!-- 使用bool类型充当属性check 字符串和花括号之间不要存在空格,否则会导致识别识别 --><checkboxchecked="{{isChecked}}"></checkbox><!-- 对象类型 --><view>昵称:{{user.nickName}},年龄{{user.age}}</view>
再了解一下,其他一些基本运算。
<!-- 算数运算 --><view>{{a + b}}</view><!-- 三元运算 --><viewhidden="{{flag ? true : false}}"> Hidden </view><!-- 逻辑判断 --><viewwx:if="{{length > 5}}"> 今日刷题挑战成功 </view><viewwx:else>今日刷题挑战失败</view>
1.3、列表渲染
列表渲染,其实说白了就是我们说的数组循环。
列表渲染,关键字:
wx:for
wx:for-item
wx:for-index
wx:key
wx:for="{{list1}}"wx:for-item="循环项的名字" => wx:for-item="item" wx:for-index="索引项的名字" => wx:for-index="index""循环项的名字" 默认 = “item”"索引项的名字" 默认 = “index”
值有两种: 1)当对数组对象做循环的时候,
list1:[{id:'1', name: '马原'},{id:'2', name: '毛中特'},{id:'3', name: '思修'},{id:'4', name: '近代史'}]wx:key="id" => item.id
2) 当数组是普通数组,
list1: ['马原', '毛中特', '思修', '近代史']wx:key="*this"
index.js
Page({data: {// 普通数组list1: ['马原', '毛中特', '思修', '近代史'],// 对象数组的循环list2: [{id:'1', name: '马原'},{id:'2', name: '毛中特'},{id:'3', name: '思修'},{id:'4', name: '近代史'}]}})
index.wxml
<view><view>普通数组</view><viewwx:for="{{list1}}"wx:key="*this">{{index}} --- {{item}}</view><view>======================</view></view><view><view>对象数组</view><viewwx:for="{{list2}}"wx:key="id">{{index}}:{{item.name}}--{{item.id}}</view></view>
1.4、条件渲染
1)wx:if
if 、else、 else if 对应微信小程序分别为 wx:if、 wx:else、 wx:elif
<viewwx:if="{{length > 5}}"> 1 </view><viewwx:elif="{{length > 2}}"> 2 </view><viewwx:else> 3 </view>
2)hidden
在标签上直接加属性hidden
3)什么场景下使用哪一个?
当标签不是频繁的切换显示,优先使用wx:if 直接把标签从页面结构给移除掉;
当表示频繁的切换显示,优先使用hiddem 通过添加样式的方式来切换显示。
1.5、事件的绑定
1)绑定事件通过 bind+事件名; 2)定义事件的回调需要放在 js文件和data同层级。
.wxml
<viewbindtap="handleTap">{{num}}</view>
.js
Page({data: {num: 0},// 声明了点击事件的回调handleTap() {let num = this.data.num;num++;this.setData({num})}})
2、样式WXSS
WXSS( WeiXin Style Sheets )是⼀套样式语言,用于描述 WXML 的组件样式。 与 CSS 相比,
WXSS 扩展的特性有:
响应式长度单位 rpx
样式导入
2.1、app.wxss
app.wxss是默认的全局样式 。把全局的样式的代码都写到这里:
page{background-color: aqua;}
page 标签是页面最外层的标签。
2.2、其他样式
1)在wxss中 不支持 通配符 `*` 当我们要实现以下功能的时候,
*{margin: 0;padding: 0;box-sizing: border-box;}
只能够单个标签一个一个的定义了!!!
page,view,text{margin: 0;padding: 0;box-sizing: border-box;}
2.3、小程序中的单位 rpx
功能和以前移动端的web中的`rem` 类似 ,`rpx`(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为`750rpx` 。 1)不管屏幕多宽 , 都是 `750rpx`; 2)不管手机屏幕多宽 都是 100% ;
2.4、样式导入
@import"../../styles/common.wxss";
通过@Import 引入,用的是相对路径。
3、生命周期
只是一个事件而已!! 只是会在特定的时候,会自动触发 。
分为两种:
1. 应用的生命周期 `app.js`;
2. 页面的生命周期 ;
一个微信小程序项目其实一个`应用`,一个应用里面可以拥有多个 `页面`。
3.1、应用的生命周期
看看考研刷题小程序项目中的app.js
App({// 小程序在启动的时候 触发 onLaunch: function (options) {// 当应用开始启动的时候,可以获取用户的一些信息 console.log("onLaunch");},// 小程序被展示 的时候触发 // 反复被触发 onShow: function (options) {console.log("onShow");},// 小程序被隐藏的时候触发onHide: function () {console.log("onHide");},// 当应用出错了时候会 触发// 在这里 捕获错误信息 // 把错误信息收集 - 发送ajax异步请求 发送到后台中 onError: function (msg) {// msg :错误信息console.log("onError");console.log(msg);},// 当页面找不到了 就会触发了 onPageNotFound: function (options) {},// 应用的全局数据globalData: {title:"生命周期"}});
3.2、页面的生命周期
看看考研刷题小程序项目中的首页index.js
Page({data: {},// 页面开始加载的时候触发 // 发送异步请求 获取数据来渲染页面 onLoad: function(options) {console.log("onLoad");},// 页面标签都渲染完毕 才触发 onReady: function() {console.log("onReady");},// 页面被 显示 页面切换-页面路由 onShow: function() {console.log("onShow");},// 页面被隐藏onHide: function() {console.log("onHide");},// 页面被 卸载的时候 - 当页面切换的时候 使用了不同的 open-type 会关闭当前页面的onUnload: function() {// 可以关闭一些定时任务 console.log("onUnload");},// 当页面 下拉刷新的时候触发 // 在全局配置或者 页面配置中 手动开启 下拉刷新!!!onPullDownRefresh: function() {console.log("onPullDownRefresh");},// 上拉页面 上拉加载下一页数据onReachBottom: function() {console.log("onReachBottom");},// 当页面被转发的时候 onShareAppMessage: function() {console.log("onShareAppMessage");},// 页面被滚动的时候 onPageScroll: function() {console.log("onPageScroll");},// 当点击tabbar的时候触发 onTabItemTap:function(item) {}});
4、原生组件
在考研刷题小程序中,常用的原生组件:
4.1、view
视图容器,也就是块级元素。
4.2、text
文本标签,也就是行内元素。
1)text 组件内只支持 text 嵌套。
2)设置user-select属性,长按文本可选、复制。
3)可以对空格、回车进行解析显示。
4.3、image
1)默认的宽度和默认的高度 320 * 240。
2)内置懒加载 lazy-load。
3)mode 渲染模式:
scaleToFill: 默认值。把图片内容,拉伸到相框的大小 。
widthFix: 把图片变成了和以前web中的图片的渲染模式一样。web图片,当宽度改变的时候,高度会等比例的跟着改变。移动端开发 img width:100%。
aspectFit: 等比例拉伸图片-内容,可能会导致,image相框留出空白。
aspectFill: 等比例拉伸图片-内容,图片的内容会被截取(图片内容会撑满相框)。
4.4、button
按钮
4.5、radio
单选项目,在考研刷题小程序项目中用于单项选择题。
4.6、checkbox
多选项目,属性和单选radio大概一致。在考研刷题小程序项目中用于多项选择题。
六、题库放到云开发数据库
1、开通服务,创建表
首先需要开通云开发服务,然后创建环境,接着创建集合,以创建题库集合为例。我创建一个题库集合,然后录入题目,都是在云开发控制台可以操作的。
2、创建或导入题目
给题库表添加记录,也就是录入题目。有两种模式,默认模式和JSON模式。我这里使用默认模式录题。
3、配置权限、env
题目都录入或者导入之后,还要配置数据库权限,这样小程序前端就可以直接调用了。在app.js填写环境env。
七、前端使用SDK调用云数据库
1、实现从题库中随机抽取题目
// 获取题库-函数定义getQuestionList() {// 数据库集合的聚合操作实例activityQuestion.aggregate().match({ //类似于where,对记录进行筛选true: _.exists(true)}).sample({size: 20}).end().then(res => {// 在控制台打印数据console.log(res.list)let data = res.list || [];// 将数据从逻辑层发送到视图层,通俗的说,也就是更新数据到页面展示this.setData({questionList:data});})}
2、将用户的答题成绩保存到数据库
// 提交答卷addExamRecord(){wx.showLoading({title: '提交答卷中'});let examResult = {wrongList: this.data.wrongList,wrong: this.data.wrong,wrongListSort: this.data.wrongListSort,chooseValue: this.data.chooseValue,totalScore: this.data.totalScore};activityRecord.add({data: {...examResult,createDate: db.serverDate()}}).then(res => {// 跳转到答题结果页,查看成绩wx.redirectTo({url: '../results/results'});wx.hideLoading();})}
3、按答题成绩totalScore字段进行降序排序(totalScore越大越靠前)
getRankList() {// 数据库集合的聚合操作实例activityScore.where({_openid: _.exists(true)}).orderBy('totalScore', 'desc').get().then(res => {// 获取集合数据,或获取根据查询条件筛选后的集合数据。console.log('[云数据库] [排行榜] 查询成功')console.log(res.data)let data = res.data || [];// 将数据从逻辑层发送到视图层,通俗的说,也就是更新数据到页面展示this.setData({rankList:data});})}
八、搭建CMS
1、入口
在答题小程序的云开发控制台,点击「更多」-「内容管理」;
2、开通
勾选同意协议后,点击确定;
3、填写账号密码
填写管理员账号及密码用于登录内容管理服务平台,点击「确定」完成开通。
4、点击访问地址
开通完成后,内容管理当前页面可看到内容管理的入口链接和相关信息。点击访问地址,即可在弹出的浏览器窗口中进行内容管理的相关配置。
5、登录CMS后台
云开发控制台-更多-内容管理页面中,点击「访问地址」即可进入知识竞赛小程序的内容管理界面。
打开内容管理( CMS )后,需使用账密登录,账号密码为开通时设置的管理员账号和密码。
6、创建项目
首先,我们需要点击新建项目下方的创建新项目按钮,创建一个名为知识竞答小程序,Id 为zsjdxcx的项目。
创建完项目后,点击项目卡片,进入项目的管理页面,我们会看到项目的欢迎页面。
7、创建或导入内容模型
我们需要建立一个内容模型,描述题目所具有的属性,如:题干,选项,正确答案,分值等。我到时会提供一个数据模型给你,一键导入即可。
8、新建内容
在创建完题库的内容模型后,我们可以点击“内容集合”下的题库菜单,开始管理数据库中的题目数据。我们可以点击新建按钮,添加一个新的题目。
如下所示,填完表单后,点击创建后,即可生成一条新的题目数据。
9、管理内容
在题库内容列表页,我们可以对已有的题库内容进行管理,如编辑、删除题目,导入新的题目数据等。
如果觉得《基于微信小程序云开发实现考研题库小程序项目(完整版)》对你有帮助,请点赞、收藏,并留下你的观点哦!